SpringBoot整合Shiro实现权限控制
引言:
本文主要分享了SpringBoot整合Shiro实现权限控制的案例,Shiro的认证流程:包括环境的搭建、数据库的添加、实体类映射文件、使用源生Shiro、MD5加密后的密钥登录问题、基于注解的开发(均附源码);
文章目录
1. 新建项目
1.1 选择构建项目的类型_aliyun
2.5 项目描述
2.6 指定SpringBoot版本和需要的依赖
本项目选择2.1.14版本,加入了Lombok、Spring Web、Thymeleaf、JDBC API、MyBatis Framework、MySQL Driver依赖
2. 创建数据库
2.1 创建tb_sys_user表
CREATE TABLE `tb_sys_user` (
`userid` int(11) NOT NULL AUTO_INCREMENT,
`loginName` varchar(20) NOT NULL,
`password` varchar(255) NOT NULL,
`state` tinyint(255) DEFAULT NULL,
`createTime` datetime DEFAULT NULL,
`realname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`userid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
2.2 创建tb_user_role表
CREATE TABLE `tb_user_role` (
`user_id` int(11) NOT NULL,
`role_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.3 创建tb_sys_role表
CREATE TABLE `tb_sys_role` (
`role_id` int(11) NOT NULL AUTO_INCREMENT,
`role_name` varchar(255) NOT NULL,
`role_desc` varchar(255) DEFAULT NULL,
`if_vilid` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
2.4 创建tb_sys_permission表
CREATE TABLE `tb_sys_permission` (
`permission_id` int(11) NOT NULL AUTO_INCREMENT,
`per_name` varchar(255) DEFAULT NULL,
`menu_name` varchar(255) DEFAULT NULL,
`menu_type` varchar(255) DEFAULT NULL,
`menu_url` varchar(255) DEFAULT NULL,
`menu_code` varchar(255) DEFAULT NULL,
`parent_code` varchar(255) DEFAULT NULL,
`per_desc` varchar(255) DEFAULT NULL,
`if_vilid` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`permission_id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;
2.5 创建tb_role_permission表
CREATE TABLE `tb_role_permission` (
`role_id` int(11) NOT NULL,
`permission_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3. 配置文件
3.1 配置初始化文件application.properties
# 应用服务 WEB 访问端口
server.port=8080
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/dbtemp?characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
mybatis.mapper-locations=classpath:mapping/*Mapper.xml
mybatis.type-aliases-package=com.sx.kak.po
3.2 pom文件
<!--添加shiro依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!--添加连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.26</version>
</dependency>
4. 实体类编写
4.1 SysUser.java
package com.sx.kak.po;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* Created by Kak on 2020/9/3.
*/
@Data
public class SysUser implements Serializable{
private Integer userid;
private String loginName;
private String password;
private Integer state;
private Date createTime;
private String realname;
}
4.2 SysPerm.java
package com.sx.kak.po;
import lombok.Data;
import java.io.Serializable;
/**
* Created by Kak on 2020/9/3.
*/
@Data
public class SysPerm implements Serializable{
private Integer permId;
private String permName;
private String menuName;
private String menuType;
private String menuUrl;
private String parentCode;
private String permDesc;
private Integer ifValid;
}
5. 数据访问层接口编写
5.1 SysUserMapper.java
package com.sx.kak.mapper;
import com.sx.kak.po.SysUser;
import org.springframework.stereotype.Repository;
/**
* Created by Kak on 2020/9/3.
*/
public interface SysUserMapper {
//根据用户登录名查询用户对象
public SysUser findUserByLoginName(String username);
}
5.2 SysPermMapper.java
package com.sx.kak.mapper;
import com.sx.kak.po.SysPerm;
import java.util.List;
/**
* Created by Kak on 2020/9/3.
*/
public interface SysPermMapper {
//根据用户名查询权限清单
public List<SysPerm> findPermsByLoginName(String username);
}
6. Mybatis映射
在resources/mapping下创建对应的映射
6.1 SysUserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http//mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sx.kak.mapper.SysUserMapper">
<select id="findUserByLoginName" parameterType="String" resultType="com.sx.kak.po.SysUser">
SELECT * FROM tb_sys_user WHERE loginName =#{username}
</select>
</mapper>
6.2 SysPerMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http//mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sx.kak.mapper.SysPermMapper">
<sql id="permColums">
p.permission_id permId,
per_name permName,
menu_name menuName,
menu_type menuType,
menu_url menuUrl,
menu_code menuCode,
parent_code parentCode,
per_desc permDesc,
p.if_vilid ifValid
</sql>
<select id="findPermsByLoginName" parameterType="String" resultType="com.sx.kak.po.SysPerm">
select
<include refid="permColums"/>
from
tb_sys_user u ,
tb_user_role ur,
tb_sys_role r,
tb_role_permission rp,
tb_sys_permission p
where
u.userid = ur.user_id
and ur.role_id = r.role_id
and r.role_id = rp.role_id
and rp.permission_id = p.permission_id
and loginName=#{username}
</select>
</mapper>
7. 业务层开发
在service包下创建
7.1 SysPermService
package com.sx.kak.servier;
import com.sx.kak.po.SysPerm;
import com.sx.kak.po.SysUser;
import java.util.List;
/**
* Created by Kak on 2020/9/3.
*/
public interface SysPermService {
//根据用户名查询用户信息
public SysUser findUserByNameService(String username);
//根据用户名查询权限信息
public List<SysPerm> findPermsByNameService(String username);
}
7.2 SysPermServiceImpl
package com.sx.kak.servier.impl;
import com.sx.kak.mapper.SysPermMapper;
import com.sx.kak.mapper.SysUserMapper;
import com.sx.kak.po.SysPerm;
import com.sx.kak.po.SysUser;
import com.sx.kak.servier.SysPermService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Created by Kak on 2020/9/3.
*/
@Service
public class SysPermServiceImpl implements SysPermService{
@Autowired(required = false)
private SysUserMapper userMapper;
@Autowired(required = false)
private SysPermMapper permMapper;
@Override
public SysUser findUserByNameService(String username) {
SysUser userByLoginName = userMapper.findUserByLoginName(username);
return userByLoginName;
}
@Override
public List<SysPerm> findPermsByNameService(String username) {
List<SysPerm> permsByLoginName = permMapper.findPermsByLoginName(username);
return permsByLoginName;
}
}
8. 前端页面
前端只是简单的提示信息,不是重点;
9. 核心板块编写_初级版本
9.1 控制层接口开发_ShiroController
完成界面的跳转,登录处理、登出处理
package com.sx.kak.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Created by Kak on 2020/9/3.
*/
@Controller
public class ShiroController {
@RequestMapping("/login")
public String showLogin(){
return "login";
}
@RequestMapping("/one")
public String showOne(){
return "one";
}
@RequestMapping("/two")
public String showTwo(){
return "two";
}
@RequestMapping("/unauth")
public String showUnauth(){
return "unauth";
}
@RequestMapping("/main")
public String showMain(){
return "main";
}
//登录处理
@RequestMapping(value = "/dealLogin",method = RequestMethod.POST)
public String dealLogin(@RequestParam("username") String username,@RequestParam("password") String password){
//从安全管理器中获取主体对象
Subject subject = SecurityUtils.getSubject();
//构建令牌对象
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try{
//使用主体的login方法判定用户的权限
subject.login(token);
if(subject.isAuthenticated()){
return "main";
}
}catch (AuthenticationException ae){
System.out.println(ae.getMessage());
}
return "login";
}
//登出处理
@RequestMapping(value = "logout",method = RequestMethod.GET)
public String logOut(){
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "login";
}
}
9.2 关于shiro的开发
9.2.1 自定义安全策略
package com.sx.kak.shiro;
import com.sx.kak.po.SysPerm;
import com.sx.kak.po.SysUser;
import com.sx.kak.servier.SysPermService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 自定义安全策略
* Created by Kak on 2020/9/3.
*/
public class MyShiroRealm extends AuthorizingRealm{
@Autowired
private SysPermService permService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
Object primaryPrincipal = principalCollection.getPrimaryPrincipal();
//根据用户名查询用户权限
List<SysPerm> permsByNameService = permService.findPermsByNameService((String) primaryPrincipal);
if(permsByNameService!=null){
SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
//权限去重
Set<String> perms = new HashSet<String>();
for (SysPerm perm:permsByNameService){
perms.add(perm.getPermName());
}
//给shiro的安全管理器授权
simpleAuthenticationInfo.setStringPermissions(perms);
return simpleAuthenticationInfo;
}
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
Object principal = authenticationToken.getPrincipal();
//根据用户名查询用户信息
SysUser userByNameService = permService.findUserByNameService((String) principal);
if(userByNameService!=null){
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, userByNameService.getPassword(), getName());
return simpleAuthenticationInfo;
}
return null;
}
}
9.2.2 自定义Shiro配置管理
package com.sx.kak.config;
import com.sx.kak.shiro.MyShiroRealm;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
/**
* 自定义shiro配置管理
* 程序加载时,已经初始化
* Created by Kak on 2020/9/3.
*/
@Configuration //标注此类为一个配置管理类,自动备spring管理
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
//创建一个Shiro的拦截过滤器对象
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//给过滤器设定安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String,String> map = new HashMap<>();
//对/main的请求需要认证后才可访问
map.put("/main","authc");
//用户必须登录后且拥有user_edit权限才可访问/one
map.put("/one","perms[user_edit]");
//用户必须登录后且拥有user_forbidden权限才可访问/two
map.put("/two","perms[user_forbidden ]");
//配置shiro过滤器拦截策略
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
//用户无权访问时,导航的地址
shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");
//其他需要用户访问的登录导航
shiroFilterFactoryBean.setLoginUrl("/login");
return shiroFilterFactoryBean;
}
@Bean(name = "securityManager")
public DefaultWebSecurityManager securityManager(@Qualifier("myRealm") AuthorizingRealm authorizingRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 给安全管理器配置安全策略
securityManager.setRealm(authorizingRealm);
return securityManager;
}
@Bean(name = "myRealm")
public MyShiroRealm myShiroRealm(){
//创建自定义的安全策略
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
}
9.3 初级整合功能测试
9.4 流程思路
在login页面admin登录,跳转到index界面,对one页面有权限,跳转one页面,对two页面无权限跳转到unauth页面,登出返回到登录页面;
10. 核心板块编写_使用Shiro的注解
在开发中使用手工注入,会增大开发的工作量,因此使用注解,在需要设置权限的地方加上注解,可以缓解该情况;
10.1 修改ShiroConfig
在ShiroConfig.java中注释掉原先使用路径过滤的权限拦截语句
10.2 开启Shiro注解
在ShiroConfig.java类中添加开启Shiro的注解
- 开启Shiro注解(@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,配置两个bean:DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor;
//开启Shiro注解(如@RequiresRoles,@RequiresPermissions),
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
//开启aop注解支持
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
return authorizationAttributeSourceAdvisor;
}
10.3 修改UserController.java
在UserController.java中需要添加权限的URL的位置添加注解
10.4 测试
当登录成功后,访问有权限的正常访问;没有权限的会出现以下界面;回台会抛出UnauthorizedException异常;
10.5 aop拦截抛出的异常
在执行过程中,如果没有error界面,或者其他情况没有走到Shiro的异常处理时,为了保证代码的合理性加入AOP拦截;抛出相应的异常后跳转到指定页面;
package com.sx.kak.exception;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
* Created by Kak on 2020/9/3.
*/
@ControllerAdvice //标识此类为一个捕获controller的通知(aop)
public class GlobalExceptionController {
@ExceptionHandler(value={UnauthorizedException.class})
public String handlerException(){
return "/unauth";
}
}
加入AOP拦截,成功拦截该异常;
11. 核心板块编写_ShiroMD5加密
在数据库表中存的密码应该是加密后的密文不应该是明文,使用MD5加密算法;
11.1 生成MD5密钥的两种方法
@Test
public void testMd51(){
String pwd ="1234";
String salt ="admin2";
Md5Hash md5Hash = new Md5Hash(pwd,salt,2);
String string1 = md5Hash.toString();
System.out.println(string1);
SimpleHash md5 = new SimpleHash("MD5", pwd, salt, 2);
System.out.println(md5.toString());
}
3511f3360d453c63dd74c95303dcca51
11.2 修改ShiroConfig.java
在ShiroConfig.java中加入HashedCredentialsMatcher,设定匹配算法的名称、hash的次数并在自定义的策略里面添加凭证匹配对象;
11.3 修改MyShiroRealm.java
修改MyShiroRealm中的认证,加入加盐操作;
12. 加入注解和加密操作代码
改动较大的代码
12.1 ShiroConfig.java
package com.sx.kak.config;
import com.sx.kak.shiro.MyShiroRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
/**
* 自定义shiro配置管理
* 程序加载时,已经初始化
* Created by Kak on 2020/9/3.
*/
@Configuration //标注此类为一个配置管理类,自动备spring管理
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
//创建一个Shiro的拦截过滤器对象
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//给过滤器设定安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String,String> map = new HashMap<>();
//匿名可访问
map.put("/before/*","anon");
//对/main的请求需要认证后才可访问
map.put("/main","authc");
//不进行手工配置过滤器访问策略,采用注解模式,将访问策略迁移至controller层
/*//用户必须登录后且拥有user_edit权限才可访问/one
map.put("/one","perms[user_edit]");
//用户必须登录后且拥有user_forbidden权限才可访问/two
map.put("/two","perms[user_forbidden ]");*/
//配置shiro过滤器拦截策略
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
//用户无权访问时,导航的地址
shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");
//其他需要用户访问的登录导航
shiroFilterFactoryBean.setLoginUrl("/login");
return shiroFilterFactoryBean;
}
@Bean(name = "securityManager")
public DefaultWebSecurityManager securityManager(@Qualifier("myRealm") AuthorizingRealm authorizingRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 给安全管理器配置安全策略
securityManager.setRealm(authorizingRealm);
return securityManager;
}
@Bean(name = "myRealm")
public MyShiroRealm myShiroRealm(@Qualifier("credentialsMatcher") CredentialsMatcher credentialsMatcher){
//创建自定义的安全策略
MyShiroRealm myShiroRealm = new MyShiroRealm();
//给自定义的realm添加凭证匹配器对象
myShiroRealm.setCredentialsMatcher(credentialsMatcher);
return myShiroRealm;
}
@Bean(name = "credentialsMatcher")
public CredentialsMatcher credentialsMatcher(){
//创建一个凭证匹配器对象
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
//设值匹配器算法名称
credentialsMatcher.setHashAlgorithmName("MD5");
//设值hash次数
credentialsMatcher.setHashIterations(2);
return credentialsMatcher;
}
//开启Shiro注解(如@RequiresRoles,@RequiresPermissions),
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
//开启aop注解支持
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
return authorizationAttributeSourceAdvisor;
}
}
12.2 MyShiroRealm.java
package com.sx.kak.shiro;
import com.sx.kak.po.SysPerm;
import com.sx.kak.po.SysUser;
import com.sx.kak.servier.SysPermService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 自定义安全策略
* Created by Kak on 2020/9/3.
*/
public class MyShiroRealm extends AuthorizingRealm{
@Autowired
private SysPermService permService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
Object primaryPrincipal = principalCollection.getPrimaryPrincipal();
//根据用户名查询用户权限
List<SysPerm> permsByNameService = permService.findPermsByNameService((String) primaryPrincipal);
if(permsByNameService!=null){
SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
//权限去重
Set<String> perms = new HashSet<String>();
for (SysPerm perm:permsByNameService){
perms.add(perm.getPermName());
}
//给shiro的安全管理器授权
simpleAuthenticationInfo.setStringPermissions(perms);
return simpleAuthenticationInfo;
}
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
Object principal = authenticationToken.getPrincipal();
//根据用户名查询用户信息
SysUser userByNameService = permService.findUserByNameService((String) principal);
if(userByNameService!=null){
//SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, userByNameService.getPassword(), getName());
//获取名字
String salt =userByNameService.getLoginName();
//将名字设置为盐
ByteSource mysalt = ByteSource.Util.bytes(salt);
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, userByNameService.getPassword(),mysalt, getName());
return simpleAuthenticationInfo;
}
return null;
}
}
12.3 ShiroController.java
package com.sx.kak.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Created by Kak on 2020/9/3.
*/
@Controller
public class ShiroController {
@RequestMapping("/login")
public String showLogin(){
return "login";
}
@RequestMapping("/one")
@RequiresPermissions(value={"user_edit"}) //此请求需要user_edit权限才可访问
public String showOne(){
return "one";
}
@RequestMapping("/two")
@RequiresPermissions(value={"user_forbidden"}) //此请求需要user_forbidden权限才可访问
public String showTwo(){
return "two";
}
@RequestMapping("/unauth")
public String showUnauth(){
return "unauth";
}
@RequestMapping("/main")
public String showMain(){
return "main";
}
//登录处理
@RequestMapping(value = "/dealLogin",method = RequestMethod.POST)
public String dealLogin(@RequestParam("username") String username,@RequestParam("password") String password){
//从安全管理器中获取主体对象
Subject subject = SecurityUtils.getSubject();
//构建令牌对象
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try{
//使用主体的login方法判定用户的权限
subject.login(token);
if(subject.isAuthenticated()){
return "main";
}
}catch (AuthenticationException ae){
System.out.println(ae.getMessage());
}
return "login";
}
//登出处理
@RequestMapping(value = "logout",method = RequestMethod.GET)
public String logOut(){
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "login";
}
}
12.4 运行界面
13. 整体的执行思路
- 程序开始执行,SpringBoot扫描注解,加载ShiroConfig将认证信息存入CacheManager中;
- 进入自定义策略,进行认证与数据库进行比对,成功后存入SessionManager;
- 与Controller里的登录操作接受的信息进行比对;
- 把前端输入用户名和密码封装到UsernamePasswordToken里,再把token注入到subject.login方法里,一旦执行shiro会自动调用shiroRealm里的登录验证方法;
- 进行授权,有权限isAuthenticated返回true,执行下面的代码;
- 其他权限的控制都是如此;