微人事(一)登入模組
(一)前後端分離後,前後端的資料互動關鍵橋樑—代理物件
該專案是屬於前後端分離的專案,因此前端和後端各有一個埠建立socket請求。前端採用8081埠,後端使用8080埠。為了使前端能夠呼叫後端的介面,後端能把JSON串傳回前端。就需要在前端建立一個代理物件,進行埠的對映。程式碼如下:
埠對映vue.config.js
後端使用8081埠,前端使用8080埠
let proxyObj = {};
proxyObj['/'] = {
ws: false,
target: 'http://localhost:8081',
changeOrigin: true,
pathRewrite: {
'^/': ''
}
}
module.exports = {
devServer: {
host: 'localhost',
port: 8080,
proxy: proxyObj //代理哪個物件
}
}
(二)登入模組
前端:
①、主入口:main.js
1.建立了一個主物件Vue,然後在這個物件裡面新增了router物件(用於做頁面轉發,不同路徑對應不同的元件,也就是不同的vue檔案),以及渲染的元件render,該元件目前掛載了id為app的元件(建立的元素App對應App.Vue檔案)
new Vue({
router,
render: h => h(App)
}).$mount('#app')
2.也可以在main.js裡面建立全域性物件,這樣子如果要使用到的話,就不用一個個去import了,直接呼叫this.+變數名即可
Vue.prototype.postKeyValueRequest = postKeyValueRequest
Vue.prototype.postRequest = postRequest
Vue.prototype.putRequest = putRequest
Vue.prototype.getRequest = getRequest
②、渲染的模板:App.vue
<template>//網頁渲染之後<template>標籤會自動去掉
<div id="app"> //被掛載的元件,之後渲染的東西都在這裡展現
<router-view/>//路由導航器,用於載入頁面
</div>
</template>
③、路由跳轉配置:/route/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../views/Login.vue'
import Home from '../views/Home.vue'
Vue.use(VueRouter) //把系統預設的route加上去
//定義自己的router。什麼路徑對應什麼元件的對映
const routes = [
{
path: '/',
name: 'Login',
component: Login
}, {
path: '/home',
name: 'Home',
component: Home
}
]
//建立router物件,並把他匯出去
const router = new VueRouter({
routes
})
export default router
④、登入頁 Login.vue
<template>//template標籤包起來的是登入頁面,渲染後template標籤自動去掉
<div>
//:rules:規則應用
//ref="LoginForm" 引用物件的名稱,用於引用這個表單
//:model="LoginForm" 用於繫結資料 如下面的 LoginForm{}
<el-form :rules="rules" ref="LoginForm" :model="LoginForm" class="LoginContainer">
<h3 class="LoginTitle">系統登入</h3>
<el-form-item label="使用者名稱" prop="username">
<el-input type="text" v-model="LoginForm.username" auto-complete="off" placeholder="請輸入使用者賬戶"></el-input>
</el-form-item>
<el-form-item label="密碼" prop="password">
<el-input type="password" v-model="LoginForm.password" auto-complete="off" placeholder="請輸入密碼"></el-input>
</el-form-item>
<el-form-item align="center">
<el-checkbox v-model="checked" class="LoginRemeber">記住我</el-checkbox>
</el-form-item>
<el-form-item>
//@click="submitLogin" 繫結點選事件,也就是點選登入按鈕後呼叫submitLogin方法
<el-button type="primary" style="width: 100%" @click="submitLogin">登入</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "login", //vue檔案的名字,預設給出
data() { //全域性的資料,主要用於初始化資料用的
return {
checked: true,
LoginForm: { //表單的初始值,如繫結的username為admin,password為123
username: 'admin',
password: '123'
},
rules: { //欄位校驗規則
username: [{required: true, message: '請輸入賬戶', tigger: 'blur'}],
password: [{required: true, message: '請輸入密碼', tigger: 'blur'}]
}
}
},
methods:{ //方法區,在這裡定義需要呼叫的方法
submitLogin(){
//ref="LoginForm"用於這裡,.validate執行了校驗方法,根據LoginForm裡面的:rules裡面的規則進行校驗
this.$refs.LoginForm.validate((valid)=>{
if(valid){
//如果檢驗為true,就呼叫登入方法postKeyValueRequest,
該方法呼叫後端介面/doLogin,然後把LoginForm裡面的引數如username和password傳入方法中,然後返回resp,如果resp有內容,則說明登入成功(因為postKeyValueRequest方法的底層方法axios.interceptors.response.use(),當登入失敗時返回的是空值)
console.log(this.LoginForm)
this.postKeyValueRequest('/doLogin',this.LoginForm).then(resp=>{
if(resp){
window.sessionStorage.setItem("user",JSON.stringify(resp.obj));
this.$router.replace("/home");
}
})
}else{
this.$message.error("請輸入所有欄位");
return false;
}
}
);
}
}
}
</script>
//樣式
<style>
.LoginContainer {
border-radius: 15px;
background-clip: padding-box;
margin: 180px auto;
width: 350px;
padding: 15px 35px 15px 35px;
background: #ffffff;
border: 1px solid #eaeaea;
box-shadow: 0 0 25px #cac6c6;
}
.LoginTitle{
margin: 20px auto 20px auto;
text-align: center;
color: #505458;
}
.LoginRemeber{
}
</style>
⑤、API檔案:/utils/api.js
前端執行登入的方法:postKeyValueRequest()
export const postKeyValueRequest = (url, params) => {
return axios({//相當於JS裡面的ajax
method: 'post',
url: `${base}${url}`,
data: params,
transformRequest: [function (data) { //對路徑和對應的索引進行轉義
let ret = '';
for (let i in data) {
//encodeURIComponent():因為在作用與url當作引數傳遞的時候,如引數出現空格這樣的特殊欄位,後臺只可以讀取到空格前的內容,後面內容丟失,造成資料讀取失敗,但是如果用encodeURIComponent()包裹一下,那會將這些特殊字元進行轉義,這樣後臺就可以成功讀取了,所以encodeURIComponent()用於url作為引數傳遞的場景中使用
ret += encodeURIComponent(i) + '=' + encodeURIComponent(data[i]) + '&'
}
return ret;
}],
headers: {
//把物件頭改為表單提交的型別
'Content-Type': 'application/x-www-form-urlencoded'
}
});
}
axios攔截器,相當於ajax裡面的success方法和error方法,主要是根據後端傳來的JSON串對前端的資料進行一點的修飾再將其傳出去
axios.interceptors.response.use(
success => { //如果方法執行成功
if (success.status && success.status == 200 && success.data.status == 500) {
Message.error({message: success.data.msg})
return;//此時返回空,表示如果請求失敗了,就彈出錯誤訊息後,什麼都不返回了
}
return success.data; //如果請求成功了 就返回資料(JSON串)
}, error => {
if (error.response.status == 504 || error.response.status == 404) {
Message.error({message: "伺服器被吃了!"})
} else if (error.response.status == 403) {
Message.error({messgae: "許可權不足"})
} else if (error.response.status == 401) {
Message.error({message: "尚未登入,請登入"})
} else {
if (error.response.data.msg) {
Message.error({message: error.response.data.msg})
} else {
Message.error({message: "未知錯誤!"})
}
}
return;
})
後端
①、實體類:Hr.java----->由於要整合Spring Security,因此實體類需要實現UserDtails介面,以便之後做許可權管理和username和password的校驗
public class Hr implements UserDetails {
private Integer id;
private String name;
private String phone;
private String telephone;
private String address;
private Boolean enabled;
private String username;
private String password;
private String userface;
private String remark;
@Override
//賬號是否過期
public boolean isAccountNonExpired() {
return true;
}
//賬號是否被鎖定
@Override
public boolean isAccountNonLocked() {
return true;
}
//密碼是否過期
@Override
public boolean isCredentialsNonExpired() {
return true;
}
//賬號是否被禁用
@Override
public boolean isEnabled() {
return enabled;
}
//該賬號對應的許可權
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
②、Mapper類:HrMapper.java
public interface HrMapper {
int deleteByPrimaryKey(Integer id);
int insert(Hr record);
int insertSelective(Hr record);
Hr selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(Hr record);
int updateByPrimaryKey(Hr record);
Hr loadUserByUsername(String username);
}
③、Service類:HrService.java---->由於Spring Security在做username和password的校驗和查詢相應的管理的時候需要查詢資料庫,因此需要實現UserDetailsService介面,實現loadUserByUsername方法,通過該方法獲取對應的使用者資訊,從而執行引數校驗和許可權管理。
@Service
public class HrService implements UserDetailsService {
//使用者是HR,這個Service相當於User Service
@Autowired
private HrMapper hrMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Hr hr = hrMapper.loadUserByUsername(username);
if(hr==null){
throw new UsernameNotFoundException("使用者名稱不存在");
}
return hr;
}
}
④、SecurityConfig.java ---->SpringSecurity起作用的話需要進行相應的配置,指定doLogin介面讓前端呼叫,由於實體類實現了UserDetails,Service類實現了UserDetailsService介面,因此後端在執行loginProcessingUrl()方法時底層會去檢驗賬戶密碼,確保登入成功還是失敗,然後將對應的東西寫成Json串寫到httpResponse中讓前端獲取(axios.interceptors.response.use())並執行相應的操作。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private HrService hrService;
//用於加密
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(hrService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()//所有請求都得被security認證
.and()
.formLogin()//表單登入
.usernameParameter("username")//使用者名稱引數
.passwordParameter("password")//密碼引數
.loginProcessingUrl("/doLogin")//登入執行的介面,也就是按下登入按鈕的時候呼叫的介面
.loginPage("/login")//返回的登入頁,若沒有配置,則spring security會預設配置一個登入頁,由於現在是前後端分離,因此之後這裡返回的是一個JSON串
.successHandler(new AuthenticationSuccessHandler() {//登入成功後的處理器
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
//httpServletRequest:請求
//httpServletResponse:響應
//authentication:儲存的登入使用者的資訊
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
Hr hr = (Hr) authentication.getPrincipal();
//登入成功後,構造返回資訊的JSON物件
//這裡把密碼設定為空的原因是防止登入後,後端返回給前端的資料中包含密碼
//導致密碼洩露
hr.setPassword(null);
RespBean ok = RespBean.ok("登入成功!", hr);
//把JSON物件寫成JSON串
String s = new ObjectMapper().writeValueAsString(ok);
out.write(s);
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() {//登入失敗的處理器
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
//httpServletRequest:請求
//httpServletResponse:響應
//AuthenticationException:登入失敗後捕獲到的異常
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
RespBean error = RespBean.error("登入失敗");
if(e instanceof LockedException){
error.setMsg("賬戶被鎖定,請聯絡管理員");
}else if(e instanceof CredentialsExpiredException){
error.setMsg("密碼過期,請聯絡管理員");
}else if(e instanceof AccountExpiredException){
error.setMsg("賬戶過期,請聯絡管理員");
}else if(e instanceof DisabledException){
error.setMsg("賬戶被禁用,請聯絡管理員");
}else if(e instanceof BadCredentialsException){
error.setMsg("使用者名稱或者密碼輸入錯誤,請重新登入");
}
out.write(new ObjectMapper().writeValueAsString(error));
out.flush();
out.close();
}
})
.permitAll()
.and()
.logout()//退出登入
.logoutSuccessHandler(new LogoutSuccessHandler() {//退出登入成功的處理器
@Override
public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.write(new ObjectMapper().writeValueAsString(RespBean.ok("登出成功")));
out.flush();
out.close();
}
})
.permitAll()
.and()
.csrf().disable();//關閉防止CSRF攻擊
}
}
⑤、RespBean.java---->用於封裝JSON串的內容
public class RespBean {
private Integer status;
private String msg;
private Object obj;
public static RespBean ok(String msg){
return new RespBean(200,msg,null);
}
public static RespBean ok(String msg,Object obj){
return new RespBean(200,msg,obj);
}
public static RespBean error(String msg){
return new RespBean(500,msg,null);
}
public static RespBean error(String msg,Object obj){
return new RespBean(500,msg,obj);
}
private RespBean() {
}
private RespBean(Integer status, String msg, Object obj) {
this.status = status;
this.msg = msg;
this.obj = obj;
}
Getter和Setter方法及toString方法
相關文章
- Spring Security 如何新增登入驗證碼?鬆哥手把手教你給微人事新增登入驗證碼Spring
- Flask Session 登入認證模組FlaskSession
- vueDemo PartOne 登入模組 +iviewVueView
- iOS登入模組有多難?iOS
- 如何設計APP登入模組?APP
- APP「登入註冊模組」詳解APP
- JdonJive3的登入模組問題
- lenve/vhr: 微人事是一個前後端分離的人力資源管理系統後端
- appium 資料引數化 登入模組APP
- 使用者註冊/登入模組實踐
- 【網頁登入】QQ 登入、微信登入、微博登入、GitHub 登入網頁Github
- 使用 Abp.Zero 搭建第三方登入模組(一):原理篇
- 前端微模組更值得被推崇!前端
- SAP Commerce Cloud ASM 模組的登入過程CloudASM
- [BUG反饋]手機端會員登入模組報錯
- 移動IM開發指南3:如何優化登入模組優化
- 關於QQ郵箱登入提示一鍵登入解決方案
- 登入模組 使用者認證 SpringSecurity +Oauth2+JwtSpringGseOAuthJWT
- Spring Security 一鍵接入驗證碼登入和小程式登入Spring
- [API 寫法] QQ 登入、微信登入、Facebook、google、蘋果登入APIGo蘋果
- FTP登入時一直彈出登入視窗,就算輸入正確的賬號密碼也不能登入FTP密碼
- Flutter關於一個登入頁Flutter
- ubuntu登入時出現“一閃之後回到登入介面”的現象Ubuntu
- mysql localhost登入和tcp/ip登入MySqllocalhostTCP
- 自己寫的一個小小的php登陸模組薦PHP
- android開發我的新浪微部落格戶端-登入頁面UI篇(4.1)AndroidUI
- 用FishRedux完成一個登入頁面Redux
- CAS單點登入(SSO)實戰(一)
- 登入介面設計之一:總體
- 使用Vue寫一個登入頁面Vue
- 第二章-開發社群登入模組-1-傳送郵件
- REMOD模組化錶帶登入眾籌 錶帶中的戰鬥機REM
- uniapp 完成兩種方式登入 驗證碼登入 密碼登入APP密碼
- sqlplus 可以登入 plsql 不能登入SQL
- 手機端QQ登入openid與網站端QQ登入openid不一樣網站
- JavaScript登入JavaScript
- flask 登入Flask
- 登入功能