Spring Boot 2 整合 Shiro 框架,实现用户权限管理
source link: https://mp.weixin.qq.com/s?__biz=MzU4Njg0MzYwNw%3D%3D&%3Bmid=2247483922&%3Bidx=1&%3Bsn=f632615588b11840df3a6d17013c7058&%3Bchksm=fdf456aaca83dfbc34e13ffd4f05491e6598f3eff7bfeab28b14317cc0f95f939de08eee0c1e&%3Btoken=1459632398&%3Blang=zh_CN
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
一、Shiro简介
1、基础概念
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。作为一款安全框架Shiro的设计相当巧妙。Shiro的应用不依赖任何容器,它不仅可以在JavaEE下使用,还可以应用在JavaSE环境中。
2、核心角色
1)Subject: 认证主体
代表当前系统的使用者,就是用户,在Shiro的认证中,认证主体通常就是userName和passWord,或者其他用户相关的唯一标识。
2)SecurityManager: 安全管理器
Shiro架构中最核心的组件,通过它可以协调其他组件完成用户认证和授权。实际上,SecurityManager就是Shiro框架的控制器。
3)Realm: 域对象
定义了访问数据的方式,用来连接不同的数据源,如:关系数据库,配置文件等等。
3、核心理念
Shiro自己不维护用户和权限,通过Subject用户主体和Realm域对象的注入,完成用户的认证和授权。
二、整合SpringBoot2框架
1、核心依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
2、Shiro核心配置
@Configuration
public class ShiroConfig {
/**
* Session Manager:会话管理
* 即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;
* 会话可以是普通JavaSE环境的,也可以是如Web环境的;
*/
@Bean("sessionManager")
public SessionManager sessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
//设置session过期时间
sessionManager.setGlobalSessionTimeout(60 * 60 * 1000);
sessionManager.setSessionValidationSchedulerEnabled(true);
// 去掉shiro登录时url里的JSESSIONID
sessionManager.setSessionIdUrlRewritingEnabled(false);
return sessionManager;
}
/**
* SecurityManager:安全管理器
*/
@Bean("securityManager")
public SecurityManager securityManager(UserRealm userRealm, SessionManager sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setSessionManager(sessionManager);
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* ShiroFilter是整个Shiro的入口点,用于拦截需要安全控制的请求进行处理
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
shiroFilter.setLoginUrl("/userLogin");
shiroFilter.setUnauthorizedUrl("/");
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/userLogin", "anon");
shiroFilter.setFilterChainDefinitionMap(filterMap);
return shiroFilter;
}
/**
* 管理Shiro中一些bean的生命周期
*/
@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* 扫描上下文,寻找所有的Advistor(通知器)
* 将这些Advisor应用到所有符合切入点的Bean中。
*/
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
return proxyCreator;
}
/**
* 匹配所有加了 Shiro 认证注解的方法
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}
3、域对象配置
@Component
public class UserRealm extends AuthorizingRealm {
@Resource
private SysUserMapper sysUserMapper ;
@Resource
private SysMenuMapper sysMenuMapper ;
/**
* 授权(验证权限时调用)
* 获取用户权限集合
*/
@Override
public AuthorizationInfo doGetAuthorizationInfo
(PrincipalCollection principals) {
SysUserEntity user = (SysUserEntity)principals.getPrimaryPrincipal();
if(user == null) {
throw new UnknownAccountException("账号不存在");
}
List<String> permsList;
//默认用户拥有最高权限
List<SysMenuEntity> menuList = sysMenuMapper.selectList();
permsList = new ArrayList<>(menuList.size());
for(SysMenuEntity menu : menuList){
permsList.add(menu.getPerms());
}
//用户权限列表
Set<String> permsSet = new HashSet<>();
for(String perms : permsList){
if(StringUtils.isEmpty(perms)){
continue;
}
permsSet.addAll(Arrays.asList(perms.trim().split(",")));
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setStringPermissions(permsSet);
return info;
}
/**
* 认证(登录时调用)
* 验证用户登录
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken)authToken;
//查询用户信息
SysUserEntity user = sysUserMapper.selectOne(token.getUsername());
//账号不存在
if(user == null) {
throw new UnknownAccountException("账号或密码不正确");
}
//账号锁定
if(user.getStatus() == 0){
throw new LockedAccountException("账号已被锁定,请联系管理员");
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo
(user, user.getPassword(),
ByteSource.Util.bytes(user.getSalt()),
getName());
return info;
}
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
HashedCredentialsMatcher shaCredentialsMatcher = new HashedCredentialsMatcher();
shaCredentialsMatcher.setHashAlgorithmName(ShiroUtils.hashAlgorithmName);
shaCredentialsMatcher.setHashIterations(ShiroUtils.hashIterations);
super.setCredentialsMatcher(shaCredentialsMatcher);
}
}
4、核心工具类
public class ShiroUtils {
/** 加密算法 */
public final static String hashAlgorithmName = "SHA-256";
/** 循环次数 */
public final static int hashIterations = 16;
public static String sha256(String password, String salt) {
return new SimpleHash(hashAlgorithmName, password, salt, hashIterations).toString();
}
// 获取一个测试账号 admin
public static void main(String[] args) {
// 3743a4c09a17e6f2829febd09ca54e627810001cf255ddcae9dabd288a949c4a
System.out.println(sha256("admin","123")) ;
}
/**
* 获取会话
*/
public static Session getSession() {
return SecurityUtils.getSubject().getSession();
}
/**
* Subject:主体,代表了当前“用户”
*/
public static Subject getSubject() {
return SecurityUtils.getSubject();
}
public static SysUserEntity getUserEntity() {
return (SysUserEntity)SecurityUtils.getSubject().getPrincipal();
}
public static Long getUserId() {
return getUserEntity().getUserId();
}
public static void setSessionAttribute(Object key, Object value) {
getSession().setAttribute(key, value);
}
public static Object getSessionAttribute(Object key) {
return getSession().getAttribute(key);
}
public static boolean isLogin() {
return SecurityUtils.getSubject().getPrincipal() != null;
}
public static void logout() {
SecurityUtils.getSubject().logout();
}
}
5、自定义权限异常提示
@RestControllerAdvice
public class ShiroException {
@ExceptionHandler(AuthorizationException.class)
public String authorizationException (){
return "抱歉您没有权限访问该内容!";
}
@ExceptionHandler(Exception.class)
public String handleException(Exception e){
return "系统异常!";
}
}
三、案例演示代码
1、测试接口
@RestController
public class ShiroController {
private static Logger LOGGER = LoggerFactory.getLogger(ShiroController.class) ;
@Resource
private SysMenuMapper sysMenuMapper ;
/**
* 登录测试
* http://localhost:7011/userLogin?userName=admin&passWord=admin
*/
@RequestMapping("/userLogin")
public void userLogin (
@RequestParam(value = "userName") String userName,
@RequestParam(value = "passWord") String passWord){
try{
Subject subject = ShiroUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(userName, passWord);
subject.login(token);
LOGGER.info("登录成功");
}catch (Exception e) {
e.printStackTrace();
}
}
/**
* 服务器每次重启请求该接口之前必须先请求上面登录接口
* http://localhost:7011/menu/list 获取所有菜单列表
* 权限要求:sys:user:shiro
*/
@RequestMapping("/menu/list")
@RequiresPermissions("sys:user:shiro")
public List list(){
return sysMenuMapper.selectList() ;
}
/**
* 用户没有该权限,无法访问
* 权限要求:ccc:ddd:bbb
*/
@RequestMapping("/menu/list2")
@RequiresPermissions("ccc:ddd:bbb")
public List list2(){
return sysMenuMapper.selectList() ;
}
/**
* 退出测试,退出后没有任何权限
*/
@RequestMapping("/userLogOut")
public String logout (){
ShiroUtils.logout();
return "success" ;
}
}
2、测试流程
1)、登录后取得权限
http://localhost:7011/userLogin?userName=admin&passWord=admin
2)、访问有权限接口
http://localhost:7011/menu/list
3)、访问无权限接口
http://localhost:7011/menu/list2
4)、退出登录
http://localhost:7011/userLogOut
四、源代码地址
GitHub地址:知了一笑
https://github.com/cicadasmile/middle-ware-parent
码云地址:知了一笑
https://gitee.com/cicadasmile/middle-ware-parent
Recommend
-
20
一、Shiro简介 1、基础概念 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。作为一款安全框架Shiro的设计相当巧妙。Shiro的应用不依赖任何容器...
-
13
一、Security简介 1、基础概念 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了S...
-
31
明确需求 在使用 Shiro 的时候,鉴权失败一般都是返回一个错误页或者登录页给前端,特别是后台系统,这种模式用的特别多。但是现在的项目越来越多的趋向于使用前后端分离的方式开发,这时候就需要响应 Jso...
-
15
[TOC] 转载地址: http://www.spring4all.com/article/443 好文列子地址:
-
8
Spring Cloud Data Flow整合Cloudfoundry UAA服务做权限控制技术之前,先读诗书:玉骨那愁瘴雾,冰姿自有仙风。 关于Spring Cloud Data Flow这里不多介绍,有兴趣可以看下...
-
13
SpringBoot整合Shiro权限框架实战 - 陈彦斌 - 博客园 SpringBoot整合Shiro权限框架实战...
-
7
目录 前言 新建一个普通的Maven项目 基本目录结构 ├── src # │ ├── main # │ │ └── java # java代码目录 │ │ └── resources # 配置文件目录, 存...
-
3
SpringBoot中整合Shiro+Mybatis+Thymeleaf框架实现用户登录以及权限的验证(超级详细过程、效果演示) 精选 原创
-
5
官方暂时还没有适配 Spring Boot 3.X 这篇文章我们来学习如何使用 Spring Boot 集成 Apache Shiro 。安全应该是互联网公司的一道生命线,几乎任何的公司都会涉及到这方面的需求。在 Java 领域一般有 Spring Security、 Apache Shiro 等安全...
-
6
jcasbin简介: jcasbin 是一个用 Java 语言打造的轻量级开源访问控制框架https://github.com/casbin/jcasbin,是casbin的Java语言版本。目前在 GitHub 开源。jcasbin 采用了元模型的设计思想,支持多种经典的访问控制方案,如基于角色的...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK