本文属于原创,说明简介,如果有问题,可留言一起探讨
1.搭建springboot项目,这里不做概述
2.引入shiro 依赖
<!-- apache shiro
权限框架
-->
<
dependency
>
<
groupId
>
org.apache.shiro
</
groupId
>
<
artifactId
>
shiro-spring
</
artifactId
>
<
version
>
1.4.0
</
version
>
</
dependency
>
3.创建
ShiroRealm
package
wx.milk.web.controller.admin;
import
org.apache.shiro.SecurityUtils;
import
org.apache.shiro.authc.*;
import
org.apache.shiro.authz.AuthorizationInfo;
import
org.apache.shiro.authz.SimpleAuthorizationInfo;
import
org.apache.shiro.realm.AuthorizingRealm;
import
org.apache.shiro.subject.PrincipalCollection;
import
org.springframework.beans.factory.annotation.
Autowired
;
import
org.springframework.stereotype.
Component
;
import
wx.milk.service.admin.IUserService;
import
wx.milk.web.utils.SpringBeanFactoryUtils;
import
wx.query.Query;
import
wx.query.Statement;
import
wx.security.User;
import
java.util.HashSet;
import
java.util.Set;
/**
* Created by zhong.h on 2018/6/13/013.
*/
@Component
public class
ShiroRealm
extends
AuthorizingRealm {
@Autowired
private
IUserService
service
;
/*
认证
.
登录
*/
@Override
protected
AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws
AuthenticationException {
if
(
service
==
null
) {
service
= SpringBeanFactoryUtils.
getBean
(IUserService.
class
);
}
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
//
获取用户输入的
token
String account = userToken.getUsername();
Query query =
new
Query();
Statement statement =
new
Statement();
statement.setName(
"account"
);
statement.setValue(account);
query.and(statement);
User user =
service
.findByParam(query);
return new
SimpleAuthenticationInfo(user, user.getPassword(),
this
.getClass().getName());
//
放入
shiro.
调用
CredentialsMatcher
检验密码
}
/**
*
授权用户权限
*/
@Override
protected
AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
//
获取用户
User user = (User) SecurityUtils.
getSubject
().getPrincipal();
SimpleAuthorizationInfo info =
new
SimpleAuthorizationInfo();
//
获取用户角色
Set<String> roleSet =
new
HashSet<String>();
roleSet.add(
"100002"
);
info.setRoles(roleSet);
//
获取用户权限
Set<String> permissionSet =
new
HashSet<String>();
permissionSet.add(
"
权限添加
"
);
permissionSet.add(
"
权限删除
"
);
info.setStringPermissions(permissionSet);
return
info;
}
}
4.创建configuration
package
wx.milk.web.configuration;
import
org.apache.shiro.codec.Base64;
import
org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import
org.apache.shiro.web.mgt.CookieRememberMeManager;
import
org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import
org.apache.shiro.web.servlet.SimpleCookie;
import
org.springframework.context.annotation.
Bean
;
import
org.springframework.context.annotation.
Configuration
;
import
wx.milk.web.controller.admin.ShiroRealm;
import
javax.servlet.Filter;
import
java.util.LinkedHashMap;
import
java.util.Map;
/**
* Created by zhong.h on 2018/6/13/013.
*/
@Configuration
public class
ShiroConfiguration {
public
ShiroRealm shiroRealm(){
return new
ShiroRealm();
}
/**
* ShiroFilterFactoryBean
处理拦截资源文件问题。
*
注意:单独一个
ShiroFilterFactoryBean
配置是或报错的,以为在
*
初始化
ShiroFilterFactoryBean
的时候需要注入:
SecurityManager
*
* Filter Chain
定义说明
1
、一个
URL
可以配置多个
Filter
,使用逗号分隔
* 2
、当设置多个过滤器时,全部验证通过,才视为通过
* 3
、部分过滤器可指定参数,如
perms
,
roles
*
*/
@Bean
public
ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean =
new
ShiroFilterFactoryBean();
//
必须设置
SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
//
如果不设置默认会自动寻找
Web
工程根目录下的
"/login.jsp"
页面
shiroFilterFactoryBean.setLoginUrl(
"/admin/login"
);
//
登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl(
"/admin/index"
);
//
未授权界面
;
shiroFilterFactoryBean.setUnauthorizedUrl(
"/error"
);
//
自定义拦截器
Map<String, Filter> filtersMap =
new
LinkedHashMap<String, Filter>();
//
限制同一帐号同时在线的个数。
//filtersMap.put("kickout", kickoutSessionControlFilter());
shiroFilterFactoryBean.setFilters(filtersMap);
//
权限控制
map.
Map<String, String> filterChainDefinitionMap =
new
LinkedHashMap<String, String>();
//
配置不会被拦截的链接 顺序判断
//
配置退出过滤器
,
其中的具体的退出代码
Shiro
已经替我们实现了
//
从数据库获取动态的权限
// filterChainDefinitionMap.put("/add", "perms[
权限添加
]");
// <!--
过滤链定义,从上向下顺序执行,一般将
/**
放在最为下边
-->:
这是一个坑呢,一不小心代码就不好使了
;
// <!-- authc:
所有
url
都必须认证通过才可以访问
; anon:
所有
url
都都可以匿名访问
-->
//logout
这个拦截器是
shiro
已经实现好了的。
//
从数据库获取
/*List<SysPermissionInit> list = sysPermissionInitService.selectAll();
for (SysPermissionInit sysPermissionInit : list) {
filterChainDefinitionMap.put(sysPermissionInit.getUrl(),
sysPermissionInit.getPermissionInit());
}*/
shiroFilterFactoryBean
.setFilterChainDefinitionMap(filterChainDefinitionMap);
return
shiroFilterFactoryBean;
}
@Bean
public
DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager =
new
DefaultWebSecurityManager();
//
设置
realm.
securityManager.setRealm(shiroRealm());
//
自定义缓存实现 使用
redis
//securityManager.setCacheManager(cacheManager());
//
自定义
session
管理 使用
redis
//securityManager.setSessionManager(sessionManager());
//
注入记住我管理器
;
securityManager.setRememberMeManager(rememberMeManager());
return
securityManager;
}
/**
* cookie
对象
;
*
@return
*/
public
SimpleCookie rememberMeCookie(){
//
这个参数是
cookie
的名称,对应前端的
checkbox
的
name = rememberMe
SimpleCookie simpleCookie =
new
SimpleCookie(
"rememberMe"
);
//<!--
记住我
cookie
生效时间
30
天
,
单位秒
;-->
simpleCookie.setMaxAge(
2592000
);
return
simpleCookie;
}
/**
* cookie
管理对象
;
记住我功能
*
@return
*/
public
CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager cookieRememberMeManager =
new
CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
//rememberMe cookie
加密的密钥 建议每个项目都不一样 默认
AES
算法 密钥长度
(128 256 512
位
)
cookieRememberMeManager.setCipherKey(Base64.
decode
(
"3AvVhmFLUs0KTA3Kprsdag=="
));
return
cookieRememberMeManager;
}
}
5. 测试
@RequestMapping
(value =
"/signin"
)
public
String login(HttpServletRequest request, HttpSession session,
String account, String password, String validatecode)
throws
JsonManagerException {
String exception = (String) request.getAttribute(
"shiroLoginFailure"
);
if
(StringUtils.
isEmpty
(account) || StringUtils.
isEmpty
(password)) {
return null
;
}
try
{
UsernamePasswordToken token =
new
UsernamePasswordToken(account, password);
Subject subject = SecurityUtils.
getSubject
();
subject.login(token);
User user=(User) subject.getPrincipal();
session.setAttribute(
"user"
, user);
return
"/admin/index"
;
}
catch
(Exception e) {
logger
.error(e.getMessage(), e);
throw
e;
}
6。重要工具类
package
wx.milk.web.utils;
import
org.springframework.beans.BeansException;
import
org.springframework.context.ApplicationContext;
import
org.springframework.context.ApplicationContextAware;
import
org.springframework.stereotype.
Component
;
/**
* spring
加载时候,注入的
bean
的顺序是 先是
Lisener
然后是
Filter
最后是
Servlet
*
因此如果在过滤器或者监听器里面注入
service
等会是空,因为在过滤器或者监听器加载的时候
* Servlet
,
service
等还没有加载,因此是空的,所以就手动注入
*
* Created by zhong.h on 2018/6/13/013.
*/
@Component
public class
SpringBeanFactoryUtils
implements
ApplicationContextAware {
private static
ApplicationContext
applicationContext
;
@Override
public void
setApplicationContext(ApplicationContext applicationContext)
throws
BeansException {
if
(SpringBeanFactoryUtils.
applicationContext
==
null
) {
SpringBeanFactoryUtils.
applicationContext
= applicationContext;
}
}
public static
ApplicationContext getApplicationContext() {
return
applicationContext
;
}
//
根据名称(
@Resource
注解)
public static
Object getBean(String name) {
return
getApplicationContext
().getBean(name);
}
//
根据类型(
@Autowired
)
public static
<
T
>
T
getBean(Class<
T
> clazz) {
return
getApplicationContext
().getBean(clazz);
}
public static
<
T
>
T
getBean(String name, Class<
T
> clazz) {
return
getApplicationContext
().getBean(name, clazz);
}
}