SpringBoot中用SpringSecurity實現用戶登陸並返回其擁有哪些角色

注:在使用springsecurity以前咱們用普通的登陸方式前端

  一、前端發來登陸請求會帶上username,passwordjava

  二、後端根據username去數據庫查詢用戶,查不到表示用戶不存在,查到了再拿password去和數據庫進行比對web

  三、若是比對同樣把它存入session,後續實行任何操做都先從session中先判斷user存不存在spring

其實一直以來我對用戶登陸的理解就是這麼簡單,而後我發現有不少地方的登陸都五花八門,方式多了,本身也就會變得數據庫

有點糊塗,因此我在這裏就使用博客形式來理清一下思路,若是用springsecurity的話這些步驟其實框架都給咱們作了,這也是這篇博客的意義所在...apache

下面就使用springsecurity來進行登陸,有人會問爲何不用shiro來實現,其實springsecurity這個技術也存在不少年了,並非一個
json

新技術了,若是使用SSM框架確實配合shiro會香一點,可是在springboot中使用springsecurity會更方便,由於不少事情boot都幫咱們作了後端

下面就來和我一塊兒coding吧....springboot

1、建立hr(user)表、role(角色)表、hr_role(用戶角色關聯表)

 1 CREATE TABLE `hr` (  2   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'hrID',  3   `name` varchar(32) DEFAULT NULL COMMENT '姓名',  4   `phone` char(11) DEFAULT NULL COMMENT '手機號碼',  5   `telephone` varchar(16) DEFAULT NULL COMMENT '住宅電話',  6   `address` varchar(64) DEFAULT NULL COMMENT '聯繫地址',  7   `enabled` tinyint(1) DEFAULT '1',  8   `username` varchar(255) DEFAULT NULL COMMENT '用戶名',  9   `password` varchar(255) DEFAULT NULL COMMENT '密碼', 10   `userface` varchar(255) DEFAULT NULL, 11   `remark` varchar(255) DEFAULT NULL, 12   PRIMARY KEY (`id`) 13 ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8

 

1 CREATE TABLE `role` ( 2   `id` INT(11) NOT NULL AUTO_INCREMENT, 3   `name` VARCHAR(64) DEFAULT NULL, 4   `nameZh` VARCHAR(64) DEFAULT NULL COMMENT '角色名稱', 5   PRIMARY KEY (`id`) 6 ) ENGINE=INNODB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8
 1 CREATE TABLE `hr_role` (  2   `id` INT(11) NOT NULL AUTO_INCREMENT,  3   `hrid` INT(11) DEFAULT NULL,  4   `rid` INT(11) DEFAULT NULL,  5   PRIMARY KEY (`id`),  6   KEY `rid` (`rid`),  7   KEY `hr_role_ibfk_1` (`hrid`),  8   CONSTRAINT `hr_role_ibfk_1` FOREIGN KEY (`hrid`) REFERENCES `hr` (`id`) ON DELETE CASCADE,  9   CONSTRAINT `hr_role_ibfk_2` FOREIGN KEY (`rid`) REFERENCES `role` (`id`) 10 ) ENGINE=INNODB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8

2、先不急作其餘的,能夠先測試一下,下面我隨便寫了個controller【建立springboot工程時記得加上springsecurity依賴】

 1 package org.yybb.securitylogin.controller;  2 
 3 import org.springframework.web.bind.annotation.GetMapping;  4 import org.springframework.web.bind.annotation.RestController;  5 
 6 /**
 7  * @Author: Ben  8  * @CreateTime: 2020-03-12 06:00  9  */
10 @RestController 11 public class HelloController { 12     @GetMapping("/hello") 13     public String hello() { 14         return "hello "; 15  } 16 }

3、訪問hello

他會自動跳轉到springsecurity的登陸頁,而後咱們就行登陸,默認用戶名是user密碼會在控制檯隨機打印出來的,而後登陸事後就能訪問了session

 

只要引入security依賴就會把因此接口保護起來,下面咱們鏈接上數據庫使用

4、建立實體類

注意:使用springsecurity用戶類必須實現UserDetail

 

 1 package org.yybb.securitylogin.model;  2 
 3 import org.springframework.security.core.GrantedAuthority;  4 import org.springframework.security.core.userdetails.UserDetails;  5 
 6 import java.util.Collection;  7 import java.util.List;  8 
 9 /**
 10  * @Author: Ben  11  * @CreateTime: 2020-03-07 12:08  12  */
 13 public class Hr implements UserDetails {  14     private Integer id;  15 
 16     private String name;  17 
 18     private String phone;  19 
 20     private String telephone;  21 
 22     private String address;  23 
 24     private Boolean enabled;  25 
 26     private String username;  27 
 28     private String password;  29 
 30     private String userface;  31 
 32     private String remark;  33 
 34     private List<Role>roles;  35 
 36     public List<Role> getRoles() {  37         return roles;  38  }  39 
 40     public void setRoles(List<Role> roles) {  41         this.roles = roles;  42  }  43 
 44     public Integer getId() {  45         return id;  46  }  47 
 48     public void setId(Integer id) {  49         this.id = id;  50  }  51 
 52     public String getName() {  53         return name;  54  }  55 
 56     public void setName(String name) {  57         this.name = name;  58  }  59 
 60     public String getPhone() {  61         return phone;  62  }  63 
 64     public void setPhone(String phone) {  65         this.phone = phone;  66  }  67 
 68     public String getTelephone() {  69         return telephone;  70  }  71 
 72     public void setTelephone(String telephone) {  73         this.telephone = telephone;  74  }  75 
 76     public String getAddress() {  77         return address;  78  }  79 
 80     public void setAddress(String address) {  81         this.address = address;  82  }  83 
 84   /* 底下返回,不刪除就會有兩個  85  public Boolean getEnabled() {  86  return enabled;  87  }*/
 88 
 89     public void setEnabled(Boolean enabled) {  90         this.enabled = enabled;  91  }  92 
 93     public String getUsername() {  94         return username;  95  }  96 
 97     /**
 98  * 帳號是否過時、未過時  99  * 100  * @return true 101      */
102  @Override 103     public boolean isAccountNonExpired() { 104         return true; 105  } 106 
107     /**
108  * 帳號是否被鎖定、未鎖定 109  * 110  * @return true 111      */
112  @Override 113     public boolean isAccountNonLocked() { 114         return true; 115  } 116 
117     /**
118  * 密碼是否過時、未過時 119  * 120  * @return true 121      */
122  @Override 123     public boolean isCredentialsNonExpired() { 124         return true; 125  } 126 
127  @Override 128     public boolean isEnabled() { 129         return enabled; 130  } 131 
132     public void setUsername(String username) { 133         this.username = username; 134  } 135 
136     /**
137  * 返回用戶角色 138  * @return
139      */
140  @Override 141     public Collection<? extends GrantedAuthority> getAuthorities() { 142         return null; 143  } 144 
145     public String getPassword() { 146         return password; 147  } 148 
149     public void setPassword(String password) { 150         this.password = password; 151  } 152 
153     public String getUserface() { 154         return userface; 155  } 156 
157     public void setUserface(String userface) { 158         this.userface = userface; 159  } 160 
161     public String getRemark() { 162         return remark; 163  } 164 
165     public void setRemark(String remark) { 166         this.remark = remark; 167  } 168 }
View Code
 1 package org.yybb.securitylogin.model;  2 
 3 import java.io.Serializable;  4 
 5 /**
 6  * @Author: Ben  7  * @CreateTime: 2020-03-10 13:43  8  */
 9 public class Role implements Serializable { 10     private Integer id; 11 
12     private String name; 13 
14     private String nameZh; 15 
16     public Integer getId() { 17         return id; 18  } 19 
20     public void setId(Integer id) { 21         this.id = id; 22  } 23 
24     public String getName() { 25         return name; 26  } 27 
28     public void setName(String name) { 29         this.name = name == null ? null : name.trim(); 30  } 31 
32     public String getNameZh() { 33         return nameZh; 34  } 35 
36     public void setNameZh(String nameZh) { 37         this.nameZh = nameZh; 38  } 39 }
View Code
 1 package org.yybb.securitylogin.model;  2 
 3 /**
 4  * @Author: Ben  5  * @CreateTime: 2020-03-07 13:40  6  */
 7 public class RespBean {  8     private Integer status;  9     private String msg; 10     private Object obj; 11 
12     public static RespBean success(String msg) { 13         return new RespBean(200, msg, null); 14  } 15 
16     public static RespBean success(String msg, Object obj) { 17         return new RespBean(200, msg, obj); 18  } 19 
20     public static RespBean error(String msg) { 21         return new RespBean(500, msg, null); 22  } 23 
24     public static RespBean error(String msg, Object obj) { 25         return new RespBean(500, msg, obj); 26  } 27 
28     private RespBean() { 29  } 30 
31     private RespBean(Integer status, String msg, Object obj) { 32         this.status = status; 33         this.msg = msg; 34         this.obj = obj; 35  } 36 
37     public Integer getStatus() { 38         return status; 39  } 40 
41     public void setStatus(Integer status) { 42         this.status = status; 43  } 44 
45     public String getMsg() { 46         return msg; 47  } 48 
49     public void setMsg(String msg) { 50         this.msg = msg; 51  } 52 
53     public Object getObj() { 54         return obj; 55  } 56 
57     public void setObj(Object obj) { 58         this.obj = obj; 59  } 60 }
View Code

 

5、建立service和mapper和mapper.xml[service必須實現userdetaillservice接口]

 1 package org.yybb.securitylogin.service;  2 
 3 import org.springframework.beans.factory.annotation.Autowired;  4 import org.springframework.security.core.userdetails.UserDetails;  5 import org.springframework.security.core.userdetails.UserDetailsService;  6 import org.springframework.security.core.userdetails.UsernameNotFoundException;  7 import org.springframework.stereotype.Service;  8 import org.yybb.securitylogin.mapper.HrMapper;  9 import org.yybb.securitylogin.model.Hr; 10 
11 /**
12  * @Author: Ben 13  * @CreateTime: 2020-03-12 06:17 14  */
15 @Service 16 public class HrService implements UserDetailsService { 17  @Autowired 18  HrMapper hrMapper; 19  @Override 20     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 21         Hr hr = hrMapper.loadUserByUsername(username); 22         if (hr==null){ 23             throw new UsernameNotFoundException("用戶不存在"); 24  } 25         return hr; 26  } 27 }
 1 package org.yybb.securitylogin.mapper;  2 
 3 import org.apache.ibatis.annotations.Mapper;  4 import org.yybb.securitylogin.model.Hr;  5 
 6 /**
 7  * @Author: Ben  8  * @CreateTime: 2020-03-12 06:19  9  */
10 @Mapper 11 public interface HrMapper { 12 
13  Hr loadUserByUsername(String username); 14 }
 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
 3 <mapper namespace="org.yybb.securitylogin.mapper.HrMapper">
 4     <resultMap id="BaseResultMap" type="org.yybb.securitylogin.model.Hr">
 5         <id column="id" property="id" jdbcType="INTEGER"/>
 6         <result column="name" property="name" jdbcType="VARCHAR"/>
 7         <result column="phone" property="phone" jdbcType="CHAR"/>
 8         <result column="telephone" property="telephone" jdbcType="VARCHAR"/>
 9         <result column="address" property="address" jdbcType="VARCHAR"/>
10         <result column="enabled" property="enabled" jdbcType="BIT"/>
11         <result column="username" property="username" jdbcType="VARCHAR"/>
12         <result column="password" property="password" jdbcType="VARCHAR"/>
13         <result column="userface" property="userface" jdbcType="VARCHAR"/>
14         <result column="remark" property="remark" jdbcType="VARCHAR"/>
15     </resultMap>
16     <select id="loadUserByUsername" resultMap="BaseResultMap">
17         select * from Hr where username=#{username} 18     </select>
19 </mapper>

6、建立配置類

 1 package org.yybb.securitylogin.config;  2 
 3 import org.springframework.beans.factory.annotation.Autowired;  4 import org.springframework.context.annotation.Bean;  5 import org.springframework.context.annotation.Configuration;  6 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;  7 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;  8 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;  9 import org.springframework.security.crypto.password.PasswordEncoder; 10 import org.yybb.securitylogin.service.HrService; 11 
12 /** 13  * @Author: Ben 14  * @CreateTime: 2020-03-12 06:28 15  */
16 @Configuration
17 public class SecurityConfig extends WebSecurityConfigurerAdapter { 18 
19     @Autowired
20  HrService hrService; 21     @Bean
22  PasswordEncoder passwordEncoder() { 23         return new BCryptPasswordEncoder(); 24  } 25 
26     @Override
27  protected void configure(AuthenticationManagerBuilder auth) throws Exception { 28  auth.userDetailsService(hrService); 29  } 30 
31 }

再測試就能夠用數據庫裏面的用戶進行登陸啦.....

下面開始配置登陸成功、失敗、註銷

 1 package org.yybb.securitylogin.config;  2 
 3 import com.fasterxml.jackson.databind.ObjectMapper;  4 import org.springframework.beans.factory.annotation.Autowired;  5 import org.springframework.context.annotation.Bean;  6 import org.springframework.context.annotation.Configuration;  7 import org.springframework.security.authentication.*;  8 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;  9 import org.springframework.security.config.annotation.web.builders.HttpSecurity;  10 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;  11 import org.springframework.security.core.Authentication;  12 import org.springframework.security.core.AuthenticationException;  13 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;  14 import org.springframework.security.crypto.password.PasswordEncoder;  15 import org.springframework.security.web.authentication.AuthenticationFailureHandler;  16 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;  17 import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;  18 import org.yybb.securitylogin.model.Hr;  19 import org.yybb.securitylogin.model.RespBean;  20 import org.yybb.securitylogin.service.HrService;  21 
 22 import javax.servlet.ServletException;  23 import javax.servlet.http.HttpServletRequest;  24 import javax.servlet.http.HttpServletResponse;  25 import java.io.IOException;  26 import java.io.PrintWriter;  27 
 28 /**  29  * @Author: Ben  30  * @CreateTime: 2020-03-12 06:28  31  */
 32 @Configuration
 33 public class SecurityConfig extends WebSecurityConfigurerAdapter {  34 
 35     @Autowired
 36  HrService hrService;  37 
 38     @Bean
 39  PasswordEncoder passwordEncoder() {  40         return new BCryptPasswordEncoder();  41  }  42 
 43     @Override
 44  protected void configure(AuthenticationManagerBuilder auth) throws Exception {  45  auth.userDetailsService(hrService);  46  }  47 
 48     @Override
 49  protected void configure(HttpSecurity http) throws Exception {  50  http.authorizeRequests()  51                 .anyRequest().authenticated()//全部請求必須認證過才能訪問[沒有配置MyFilter,DecisionManager以前]
 52                 .and()  53  .formLogin()  54  .usernameParameter("username")  55  .passwordParameter("password")  56                 //真正的登陸接口,必須是key-value形式  57                 .loginProcessingUrl("/login.do")  58                 //返回未登陸json  59                 .loginPage("/login")  60                 //登陸成功回調  61  .successHandler(new AuthenticationSuccessHandler() {  62                     @Override  //Authentication登陸成功的用戶信息保存地  63                     public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {  64                         response.setContentType("application/json;charset=utf-8");  65                         PrintWriter out = response.getWriter();  66                         //從authentication獲得對象強轉成Hr對象  67                         Hr hr = (Hr) authentication.getPrincipal();  68                         //避免返回給頁面  69                         hr.setPassword(null);  70                         RespBean success = RespBean.success("登陸成功!", hr);  71                         //轉成字符串以便輸出  72                         String str = new ObjectMapper().writeValueAsString(success);  73                         out.write(str);  74  out.flush();  75                         out.close();  76  }  77  }).failureHandler(new AuthenticationFailureHandler() {  78             @Override  //登陸失敗  79             public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {  80                 response.setContentType("application/json;charset=utf-8");  81                 PrintWriter out = response.getWriter();  82                 RespBean error = RespBean.error("登陸失敗!");  83                 if (exception instanceof LockedException) {  84  error.setMsg("帳戶被鎖定,請聯繫管理員!");  85                 } else if (exception instanceof CredentialsExpiredException) {  86  error.setMsg("密碼過時,請聯繫管理員!");  87                 } else if (exception instanceof AccountExpiredException) {  88  error.setMsg("帳戶過時,請聯繫管理員!");  89                 } else if (exception instanceof DisabledException) {  90  error.setMsg("帳戶被禁用,請聯繫管理員!");  91                 } else if (exception instanceof BadCredentialsException) {  92  error.setMsg("用戶名或密碼輸入錯誤,請從新輸入!");  93  }  94                 //轉成字符串以便輸出  95  out.write(new ObjectMapper().writeValueAsString(error));  96  out.flush();  97                 out.close();  98  }  99  }).permitAll() 100                 .and() 101  .logout() 102  .logoutSuccessHandler(new LogoutSuccessHandler() { 103                     @Override  //註銷功能,默認接口logout 104                     public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { 105                         response.setContentType("application/json;charset=utf-8"); 106                         PrintWriter out = response.getWriter(); 107  out.write(new ObjectMapper().writeValueAsString(RespBean.success("註銷成功!"))); 108  out.flush(); 109                         out.close(); 110  } 111  }).permitAll() 112                 //postman測試 113                 .and() 114  .csrf().disable(); 115  } 116 }
View Code

測試

 

測試是成功了,可是角色沒有,下面把返回角色查詢出來就行,你們應該注意到,個人實體類別Hr裏面返回的角色是return null;

因此首先把它加在Hr

 1  /**
 2  * 返回用戶角色  3  * @return
 4      */
 5  @Override  6     public Collection<? extends GrantedAuthority> getAuthorities() {  7         List<SimpleGrantedAuthority>authorities=new ArrayList<>(roles.size());  8         for (Role role : roles) {  9             authorities.add(new SimpleGrantedAuthority(role.getName())); 10  } 11         return authorities; 12     }

登陸成功以後在service中給用戶設置角色

 1 //設置用戶角色 2 hr.setRoles(hrMapper.getHrRolesById(hr.getId())); 

給mapper加上方法,給xml加上SQL

1  /**
2  * 根據用戶ID查詢他擁有的角色 3  * @param id 4  * @return
5      */
6     List<Role> getHrRolesById(Integer id);
1  <select id="getHrRolesById" resultType="org.yybb.securitylogin.model.Role"> 
2 SELECT r.* FROM role r ,hr_role hrr WHERE hrr.rid=r.id AND hrr.hrid=#{id}
3 </select>

最終測試

以上就是用springsecurity實現用戶登陸返回對應角色的全過程。。

相關文章
相關標籤/搜索