奔跑在路上的Snails

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

注:在使用springsecurity之前我们用普通的登录方式

  1、前端发来登录请求会带上username,password

  2、后端根据username去数据库查询用户,查不到表示用户不存在,查到了再拿password去和数据库进行比对

  3、如果比对一样把它存入session,后续实行任何操作都先从session中先判断user存不存在

其实一直以来我对用户登录的理解就是这么简单,然后我发现有很多地方的登录都五花八门,方式多了,自己也就会变得

有点糊涂,所以我在这里就使用博客形式来理清一下思路,如果用springsecurity的话这些步骤其实框架都给我们做了,这也是这篇博客的意义所在...

下面就使用springsecurity来进行登录,有人会问为什么不用shiro来实现,其实springsecurity这个技术也存在很多年了,并不是一个

新技术了,如果使用SSM框架确实配合shiro会香一点,但是在springboot中使用springsecurity会更方便,因为很多事情boot都帮我们做了

下面就来和我一起coding吧....

一、创建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

二、先不急做其他的,可以先测试一下,下面我随便写了个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 }

三、访问hello

他会自动跳转到springsecurity的登录页,然后我们就行登录,默认用户名是user密码会在控制台随机打印出来的,然后登录过后就能访问了

 

只要引入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 }
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

 

五、创建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>

六、创建配置类

 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实现用户登录返回对应角色的全过程。。

 

posted on 2020-03-12 07:54  那二傻子  阅读(6843)  评论(0编辑  收藏  举报