注:在使用springsecurity以前咱們用普通的登陸方式前端
一、前端發來登陸請求會帶上username,passwordjava
二、後端根據username去數據庫查詢用戶,查不到表示用戶不存在,查到了再拿password去和數據庫進行比對web
三、若是比對同樣把它存入session,後續實行任何操做都先從session中先判斷user存不存在spring
其實一直以來我對用戶登陸的理解就是這麼簡單,而後我發現有不少地方的登陸都五花八門,方式多了,本身也就會變得數據庫
有點糊塗,因此我在這裏就使用博客形式來理清一下思路,若是用springsecurity的話這些步驟其實框架都給咱們作了,這也是這篇博客的意義所在...apache
下面就使用springsecurity來進行登陸,有人會問爲何不用shiro來實現,其實springsecurity這個技術也存在不少年了,並非一個
json
新技術了,若是使用SSM框架確實配合shiro會香一點,可是在springboot中使用springsecurity會更方便,由於不少事情boot都幫咱們作了後端
下面就來和我一塊兒coding吧....springboot
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
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 }
他會自動跳轉到springsecurity的登陸頁,而後咱們就行登陸,默認用戶名是user密碼會在控制檯隨機打印出來的,而後登陸事後就能訪問了session
只要引入security依賴就會把因此接口保護起來,下面咱們鏈接上數據庫使用
注意:使用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 }
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 }
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 }
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>
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 }
測試
測試是成功了,可是角色沒有,下面把返回角色查詢出來就行,你們應該注意到,個人實體類別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實現用戶登陸返回對應角色的全過程。。