欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringBoot中用SpringSecurity实现用户登录并返回其拥有哪些角色

程序员文章站 2022-11-22 10:31:54
注:在使用springsecurity之前我们用普通的登录方式 1、前端发来登录请求会带上username,password 2、后端根据username去数据库查询用户,查不到表示用户不存在,查到了再拿password去和数据库进行比对 3、如果比对一样把它存入session,后续实行任何操作都先 ......

注:在使用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

SpringBoot中用SpringSecurity实现用户登录并返回其拥有哪些角色

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

SpringBoot中用SpringSecurity实现用户登录并返回其拥有哪些角色

 

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

 

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

测试

SpringBoot中用SpringSecurity实现用户登录并返回其拥有哪些角色

 

测试是成功了,但是角色没有,下面把返回角色查询出来就行,大家应该注意到,我的实体类别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>

最终测试

SpringBoot中用SpringSecurity实现用户登录并返回其拥有哪些角色

以上就是用springsecurity实现用户登录返回对应角色的全过程。。