Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE 环境,也可以用在 JavaEE 环境。Shiro 可以帮助我们完成:认证、授权、加密、会话管理、与 Web 集成、缓存等。其基本功能点如下图所示:
我们从外部来看 Shiro ,即从应用程序角度的来观察如何使用 Shiro 完成工作。如下图:
可以看到:应用代码直接交互的对象是 Subject,也就是说 Shiro 的对外 API 核心就是 Subject;其每个 API 的含义:
Subject:主体,代表了当前 “用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都Subject,如网络爬虫,机器人等;即一个抽象概念;所有 Subject 都绑定到 SecurityManager,与 Subject 的所有交互都会委托给 SecurityManager;可以把 Subject 认为是一个门面;SecurityManager 才是实际的执行者;
SecurityManager:安全管理器;即所有与安全有关的操作都会与 SecurityManager 交互;且它管理着所有 Subject;可以看出它是 Shiro 的核心,它负责与后边介绍的其他组件进行交互,如果学习过 SpringMVC,你可以把它看成 DispatcherServlet 前端控制器;
Realm:域,Shiro 从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource,即安全数据源。
也就是说对于我们而言,最简单的一个 Shiro 应用:
从以上也可以看出,Shiro 不提供维护用户 / 权限,而是通过 Realm 让开发人员自己注入。
从 Shiro 内部来看下 Shiro 的架构,如下图所示:
在 shiro 中,用户需要提供 principals (身份)和 credentials(证明)给 shiro,从而应用能验证用户身份:
认证流程
身份信息和凭证信息会被封装成一个token,然后由SecurityManager的Authenticator 进行身份认证,认证过程中,Authenticator 会拿到realm中的数据进行匹配,如果匹配成功则验证成功进入系统。
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-coreartifactId>
<version>1.5.3version>
dependency>
[users]
zhangsan=123
lisi=456
wangmazi=123456
public class TestAuthenticator {
public static void main(String[] args) {
//创建安全管理器对象
DefaultSecurityManager securityManager=new DefaultSecurityManager();
//给安全管理器设置realm
securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
//给全局安全工具类设置安全管理器
SecurityUtils.setSecurityManager(securityManager);
//关键对象Subject主体
Subject subject = SecurityUtils.getSubject();
//创建token令牌,相当于在浏览器输入的信息
UsernamePasswordToken token=new UsernamePasswordToken("zhangsan","123");
System.out.println(subject.isAuthenticated());
//用户认证
subject.login(token);
System.out.println(subject.isAuthenticated());
}
}
运行后,控制台输入以下的结果,false表示还未进行认证,true表示认证完毕,说明认证成功。认证失败有两种情况,如果用户名不正确,则会抛出UnknownAccountException
异常;密码不正确则会抛出IncorrectCredentialsException
异常。
false
true
通过对源码的分析,最终得出用户名的校验由SimpleAccountRealm
类的doGetAuthenticationInfo()
方法实现,然后返回用户信息,接着在AuthenticatingRealm
类中实现密码的对比。
通过自定义Realm就可以实现对数据库的数据进行匹配,而不再需要shiro.ini文件进行测试。
public class MyRealm extends AuthorizingRealm {
//该方法用于授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//该方法用于验证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取token中的用户名
String principal = (String)authenticationToken.getPrincipal();
//假设zhangsan是从数据库查询出来的,若zhangsan为空则返回null
if ("zhangsan".equals(principal)){
//参数一:表示查询出来的用户名
//参数二:表示查询出来的密码
//参数三:表示使用的Realm的名称
SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(principal,"123",this.getName());
return authenticationInfo;
}else {
return null;
}
}
}
public class TestAuthenticator {
public static void main(String[] args) {
//创建安全管理器对象
DefaultSecurityManager securityManager=new DefaultSecurityManager();
//给安全管理器设置realm
securityManager.setRealm(new MyRealm());
//给全局安全工具类设置安全管理器
SecurityUtils.setSecurityManager(securityManager);
//关键对象Subject主体
Subject subject = SecurityUtils.getSubject();
//创建token令牌
UsernamePasswordToken token=new UsernamePasswordToken("zhangsan","123");
System.out.println(subject.isAuthenticated());
//用户认证
subject.login(token);
System.out.println(subject.isAuthenticated());
}
}
采用MD5+salt+散列次数
的方案对密码进行加密
//三个参数分别为密码,盐值,散列次数
Md5Hash md5Hash=new Md5Hash("123","asd123",1024);
System.out.println(md5Hash.toHex());
输出加密后的密码为f0ba563f44fb3c93352f3afaf33b5dcc
public class MyRealm extends AuthorizingRealm {
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取token中的用户名
String principal = (String)authenticationToken.getPrincipal();
//假设zhangsan是从数据库查询出来的,若zhangsan为空则返回null
if ("zhangsan".equals(principal)){
//参数一:表示查询出来的用户名
//参数二:表示查询出来的密码
//参数三:表示使用的盐值
//参数四:表示使用的Realm的名称
SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(principal,"f0ba563f44fb3c93352f3afaf33b5dcc", ByteSource.Util.bytes("asd123"),this.getName());
return authenticationInfo;
}else {
return null;
}
}
}
public class TestAuthenticator {
public static void main(String[] args) {
//创建安全管理器对象
DefaultSecurityManager securityManager=new DefaultSecurityManager();
//创建Realm
MyRealm realm=new MyRealm();
//设置realm使用hash凭证匹配器
HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
//指定算法
matcher.setHashAlgorithmName("MD5");
//指定散列次数
matcher.setHashIterations(1024);
realm.setCredentialsMatcher(matcher);
//给安全管理器设置realm
securityManager.setRealm(realm);
//给全局安全工具类设置安全管理器
SecurityUtils.setSecurityManager(securityManager);
//关键对象Subject主体
Subject subject = SecurityUtils.getSubject();
//创建token令牌
UsernamePasswordToken token=new UsernamePasswordToken("zhangsan","123");
System.out.println(subject.isAuthenticated());
//用户认证
subject.login(token);
System.out.println(subject.isAuthenticated());
}
}
授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。
if(subject.hasRole(“admin”)) {
//有权限
} else {
//无权限
};
//表示对user下面的01号用户是否有更新的权限
if(subject.isPermitted("user:update:01")){
//操作
}
格式:资源标识符:操作:资源实例标识符
例:
user:update:01
:表示对user资源的01有更新权限user:*:01
:表示对user资源的01有全部权限user:*:*
: //表示对user资源的所有实例拥有所有权限book:update:*
://表示对book资源的所有实例拥有更新权限*:*:*
://表示对所有资源拥有所有权限Shiro 支持三种方式的授权:
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有权限
} else {
//无权限
};
@RequiresRoles("admin")
public void hello() {
//有权限
};
<shiro:hasRole name="admin">
<!— 有权限 —>
</shiro:hasRole>;
本案例基于之前加密后的realm和测试类进一步开发
public class MyRealm extends AuthorizingRealm {
//用于授权的类
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获得用户名
String principal = (String)principalCollection.getPrimaryPrincipal();
//根据用户名查找数据库得到的权限
//将权限赋到 SimpleAuthorizationInfo
SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
authorizationInfo.addRole("admin");
authorizationInfo.addRole("user");
authorizationInfo.addStringPermission("user:*:*");
return authorizationInfo;
}
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取token中的用户名
String principal = (String)authenticationToken.getPrincipal();
//假设zhangsan是从数据库查询出来的,若zhangsan为空则返回null
if ("zhangsan".equals(principal)){
//参数一:表示查询出来的用户名
//参数二:表示查询出来的密码
//参数三:表示使用的盐值
//参数四:表示使用的Realm的名称
SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(principal,"f0ba563f44fb3c93352f3afaf33b5dcc", ByteSource.Util.bytes("asd123"),this.getName());
return authenticationInfo;
}else {
return null;
}
}
}
public class TestAuthenticator {
public static void main(String[] args) {
//创建安全管理器对象
DefaultSecurityManager securityManager=new DefaultSecurityManager();
//创建Realm
MyRealm realm=new MyRealm();
//设置realm使用hash凭证匹配器
HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
//指定算法
matcher.setHashAlgorithmName("MD5");
//指定散列次数
matcher.setHashIterations(1024);
realm.setCredentialsMatcher(matcher);
//给安全管理器设置realm
securityManager.setRealm(realm);
//给全局安全工具类设置安全管理器
SecurityUtils.setSecurityManager(securityManager);
//关键对象Subject主体
Subject subject = SecurityUtils.getSubject();
//创建token令牌
UsernamePasswordToken token=new UsernamePasswordToken("zhangsan","123");
//用户认证
subject.login(token);
if (subject.isAuthenticated()){
//基于单角色
System.out.println("是否具有 admin 的权限");
System.out.println(subject.hasRole("admin"));
//基于多角色
System.out.println("是否同时具有 admin、user 的权限");
System.out.println(subject.hasAllRoles(Arrays.asList("admin","user")));
//返回值封装在数组
boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "user", "super"));
System.out.println("是否具有 admin、user、super 的权限");
for (boolean aBoolean : booleans) {
System.out.println(aBoolean);
}
//基于单个资源
System.out.println("是否具有user:update:01的权限?");
System.out.println(subject.isPermitted("user:update:01"));
//基于多资源
System.out.println("是否同时具有user:update:01、book:update:01的权限?");
System.out.println(subject.isPermittedAll("user:update:01", "book:update:01"));
//返回值封装在数组
System.out.println("是否具有user:update:01、book:update:01的权限?");
boolean[] permitted = subject.isPermitted("user:update:01", "book:update:01");
for (boolean b : permitted) {
System.out.println(b);
}
}
}
}
是否具有 admin 的权限
true
是否同时具有 admin、user 的权限
true
是否具有 admin、user、super 的权限
true
true
false
是否具有user:update:01的权限?
true
是否同时具有user:update:01、book:update:01的权限?
false
是否具有user:update:01、book:update:01的权限?
true
false
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-spring-boot-starterartifactId>
<version>1.5.3version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.16version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.22version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.apache.tomcat.embedgroupId>
<artifactId>tomcat-embed-jasperartifactId>
dependency>
<dependency>
<groupId>jstlgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
server:
port: 8002
servlet:
context-path: /shiro
spring:
application:
name: shiro
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/shiro?serverTimezone=UTC
username: root
password: 123456
mvc:
view:
prefix: /
suffix: .jsp
mybatis:
type-aliases-package: com.lk.shiro.entity
mapper-locations: classpath:mapper/*.xml
@Mapper
public interface UserDao {
void insert(User user);
User findByName(String username);
User findRolesByName(String username);
List<Permission> findPermissionByName(String username);
}
<mapper namespace="com.lk.shiro.dao.UserDao">
<resultMap id="UserMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<collection property="roles" javaType="list" ofType="Role">
<id property="id" column="rid"/>
<result property="name" column="rname"/>
collection>
resultMap>
<select id="insert" parameterType="User">
insert into t_user(username,password,salt) values(#{username},#{password},#{salt})
select>
<select id="findByName" parameterType="String" resultType="User">
select * from t_user where username=#{username}
select>
<select id="findRolesByName" parameterType="String" resultMap="UserMap">
SELECT
u.id,
u.username,
r.id as rid,
r.`name` as rname
FROM
t_user AS u
LEFT JOIN t_user_role AS ur ON u.id = ur.uid
LEFT JOIN t_role AS r ON r.id = ur.rid
WHERE
u.username = #{username}
select>
<select id="findPermissionByName" parameterType="String" resultType="Permission">
SELECT
distinct p.id,
p.`name`,
p.url
FROM
t_user AS u
LEFT JOIN t_user_role AS ur ON u.id = ur.uid
LEFT JOIN t_role AS r ON r.id = ur.rid
LEFT JOIN t_role_permmision AS rp ON r.id = rp.rid
LEFT JOIN t_permission AS p ON rp.pid = p.id
WHERE
u.username = #{username}
select>
mapper>
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public void register(User user) {
//生成7位的随机盐
String salt= UUID.randomUUID().toString().replace("-","").substring(0,7);
user.setSalt(salt);
Md5Hash md5Hash=new Md5Hash(user.getPassword(),salt,1024);
user.setPassword(md5Hash.toHex());
userDao.insert(user);
}
@Override
public User findByName(String username) {
return userDao.findByName(username);
}
@Override
public List<String> findRolesByName(String username) {
List<Role> roles = userDao.findRolesByName(username).getRoles();
List<String> roleList=new ArrayList<>();
for (Role role : roles) {
roleList.add(role.getName());
}
return roleList;
}
@Override
public List<String> findPermissionByName(String username) {
List<Permission> permissions = userDao.findPermissionByName(username);
List<String> plist=new ArrayList<>();
for (Permission permission : permissions) {
if (permission!=null){
plist.add(permission.getName());
}
}
return plist;
}
}
@Controller
@RequestMapping(value = "user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = "register")
public String register(User user){
userService.register(user);
return "redirect:/login.jsp";
}
@RequestMapping(value = "login")
public String login(String username,String password){
Subject subject = SecurityUtils.getSubject();
try{
subject.login(new UsernamePasswordToken(username,password));
return "redirect:/index.jsp";
}catch (UnknownAccountException e){
e.printStackTrace();
System.out.println("用户名不存在");
}catch (IncorrectCredentialsException e){
e.printStackTrace();
System.out.println("密码错误");
}
return "redirect:/login.jsp";
}
@RequestMapping(value = "logout")
public String logout(){
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "redirect:/login.jsp";
}
}
注册页
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isELIgnored="false" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Insert title heretitle>
head>
<body>
<h1>用户注册h1>
<form action="user/register">
<label for="username">
用户名:<input id="username" name="username" type="text"/><br>
label>
<label for="password">
密码:<input id="password" name="password" type="password"/>
label>
<input type="submit" value="提交">
form>
body>
html>
主页
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isELIgnored="false" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Insert title heretitle>
head>
<body>
<h1>主页h1>
<a href="user/logout">退出用户a>
<ul>
<shiro:hasAnyRoles name="admin,user">
<li><a href="">用户管理a>
<ul>
<shiro:hasPermission name="user:*:*">
<li>添加li>
<li>修改li>
shiro:hasPermission>
<li>查看li>
ul>
li>
shiro:hasAnyRoles>
<shiro:hasRole name="admin">
<li><a href="">商品管理a>li>
<li><a href="">物流管理a>li>
shiro:hasRole>
ul>
body>
html>
登录页
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isELIgnored="false" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Insert title heretitle>
head>
<body>
<h1>用户登录h1>
<form action="user/login">
<label for="username">
用户名:<input id="username" name="username" type="text"/><br>
label>
<label for="password">
密码:<input id="password" name="password" type="password"/>
label>
<input type="submit" value="提交">
form>
body>
html>
public class MyRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String principal = (String)principalCollection.getPrimaryPrincipal();
UserService userService = (UserService) ApplicationContextUtil.getBean("userServiceImpl");
SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
List<String> roles = userService.findRolesByName(principal);
List<String> permissions=userService.findPermissionByName(principal);
if (roles.size()>0){
authorizationInfo.addRoles(roles);
if (permissions.size()>0){
authorizationInfo.addStringPermissions(permissions);
}
return authorizationInfo;
}
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String principal = (String)authenticationToken.getPrincipal();
UserService userService = (UserService) ApplicationContextUtil.getBean("userServiceImpl");
User user = userService.findByName(principal);
if (user!=null){
return new SimpleAuthenticationInfo(
principal,
user.getPassword(),
ByteSource.Util.bytes(user.getSalt()),
this.getName());
}else {
return null;
}
}
}
@Configuration
public class ShiroConfig {
//创建shiro filter,负责拦截所有请求
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean filterFactoryBean=new ShiroFilterFactoryBean();
filterFactoryBean.setSecurityManager(securityManager);
Map<String,String> map=new HashMap<>();
//设置公共资源
map.put("/user/login","anon");//设置为公共资源,不用过滤
map.put("/user/register","anon");
map.put("/register.jsp","anon");
//设置受限资源,默认重定向的路径为 /login.jsp
map.put("/**","authc");
filterFactoryBean.setFilterChainDefinitionMap(map);
return filterFactoryBean;
}
//创建安全管理器
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
//自定义realm
@Bean
public Realm getRealm(){
MyRealm realm=new MyRealm();
HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("MD5");
matcher.setHashIterations(1024);
realm.setCredentialsMatcher(matcher);
return realm;
}
}
身份验证相关的
过滤器缩写 | 功能 |
---|---|
anon | 指定url可以匿名访问 |
authc | 基于表单的拦截器;如“/**=authc”,如果没有登录会跳到相应的登录页面登录;主要属性:usernameParam:表单提交的用户名参数名( username); passwordParam:表单提交的密码参数名(password); rememberMeParam:表单提交的密码参数名(rememberMe); loginUrl:登录页面地址(/login.jsp);successUrl:登录成功后的默认重定向地址; failureKeyAttribute:登录失败后错误信息存储key(shiroLoginFailure) |
authcBasic | Basic HTTP身份验证拦截器,主要属性: applicationName:弹出登录框显示的信息(application) |
logout | 退出拦截器,主要属性:redirectUrl:退出成功后重定向的地址(/) |
user | 用户拦截器,用户已经身份验证/记住我登录的都可 |
授权相关的
过滤器缩写 | 功能 |
---|---|
roles | 角色授权拦截器,验证用户是否拥有所有角色;主要属性: loginUrl:登录页面地址(/login.jsp);unauthorizedUrl:未授权后重定向的地址;示例“/admin/**=roles[admin]” |
perms | 权限授权拦截器,验证用户是否拥有所有权限;属性和roles一样; |
port | 端口拦截器,主要属性:port(80):可以通过的端口 |
rest | rest风格拦截器,自动根据请求方法构建权限字符串 |
如果不加缓存,那么每次授权操作都要对数据库进行操作,会对数据库造成巨大的压力,因此要将认证和授权信息放到缓存中。
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.5.3</version>
</dependency>
@Bean
public Realm getRealm(){
MyRealm realm=new MyRealm();
HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("MD5");
matcher.setHashIterations(1024);
realm.setCredentialsMatcher(matcher);
realm.setCacheManager(new EhCacheManager());
realm.setCachingEnabled(true);
realm.setAuthenticationCachingEnabled(true); //开启认证缓存
realm.setAuthenticationCacheName("authenticationCache");
realm.setAuthorizationCachingEnabled(true); //开启授权缓存
realm.setAuthorizationCacheName("authorizationCache");
return realm;
}
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
public class RedisCache<k,v> implements Cache<k,v> {
private String cacheName;
public RedisCache(){}
public RedisCache(String cacheName){
this.cacheName=cacheName;
}
@Override
public v get(k k) throws CacheException {
RedisTemplate redisTemplate = getRedisTemplate();
return (v) redisTemplate.opsForHash().get(this.cacheName,k.toString());
}
@Override
public v put(k k, v v) throws CacheException {
RedisTemplate redisTemplate = getRedisTemplate();
redisTemplate.opsForHash().put(this.cacheName,k.toString(),v);
return null;
}
@Override
public v remove(k k) throws CacheException {
return (v)getRedisTemplate().opsForHash().delete(this.cacheName,k.toString());
}
@Override
public void clear() throws CacheException {
getRedisTemplate().opsForHash().delete(this.cacheName);
}
@Override
public int size() {
return getRedisTemplate().opsForHash().size(this.cacheName).intValue();
}
@Override
public Set<k> keys() {
return getRedisTemplate().opsForHash().keys(this.cacheName);
}
@Override
public Collection<v> values() {
return getRedisTemplate().opsForHash().values(this.cacheName);
}
public RedisTemplate getRedisTemplate(){
RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtil.getBean("redisTemplate");
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}
public class RedisCacheManager implements CacheManager {
@Override
public <K, V> Cache<K, V> getCache(String s) throws CacheException {
return new RedisCache<K, V>(s);
}
}
public class MyByteSource implements ByteSource,Serializable {
private byte[] bytes;
private String cachedHex;
private String cachedBase64;
public MyByteSource(){}
public MyByteSource(byte[] bytes) {
this.bytes = bytes;
}
public MyByteSource(char[] chars) {
this.bytes = CodecSupport.toBytes(chars);
}
public MyByteSource(String string) {
this.bytes = CodecSupport.toBytes(string);
}
public MyByteSource(ByteSource source) {
this.bytes = source.getBytes();
}
public MyByteSource(File file) {
this.bytes = (new MyByteSource.BytesHelper()).getBytes(file);
}
public MyByteSource(InputStream stream) {
this.bytes = (new MyByteSource.BytesHelper()).getBytes(stream);
}
public static boolean isCompatible(Object o) {
return o instanceof byte[] || o instanceof char[] || o instanceof String || o instanceof ByteSource || o instanceof File || o instanceof InputStream;
}
public byte[] getBytes() {
return this.bytes;
}
public boolean isEmpty() {
return this.bytes == null || this.bytes.length == 0;
}
public String toHex() {
if (this.cachedHex == null) {
this.cachedHex = Hex.encodeToString(this.getBytes());
}
return this.cachedHex;
}
public String toBase64() {
if (this.cachedBase64 == null) {
this.cachedBase64 = Base64.encodeToString(this.getBytes());
}
return this.cachedBase64;
}
public String toString() {
return this.toBase64();
}
public int hashCode() {
return this.bytes != null && this.bytes.length != 0 ? Arrays.hashCode(this.bytes) : 0;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o instanceof ByteSource) {
ByteSource bs = (ByteSource)o;
return Arrays.equals(this.getBytes(), bs.getBytes());
} else {
return false;
}
}
private static final class BytesHelper extends CodecSupport {
private BytesHelper() {
}
public byte[] getBytes(File file) {
return this.toBytes(file);
}
public byte[] getBytes(InputStream stream) {
return this.toBytes(stream);
}
}
}
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String principal = (String)authenticationToken.getPrincipal();
UserService userService = (UserService) ApplicationContextUtil.getBean("userServiceImpl");
User user = userService.findByName(principal);
if (user!=null){
return new SimpleAuthenticationInfo(
principal,
user.getPassword(),
new MyByteSource(user.getSalt()),
this.getName());
}else {
return null;
}
}
@Bean
public Realm getRealm(){
MyRealm realm=new MyRealm();
HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("MD5");
matcher.setHashIterations(1024);
realm.setCredentialsMatcher(matcher);
realm.setCacheManager(new RedisCacheManager());
realm.setCachingEnabled(true);
realm.setAuthenticationCachingEnabled(true); //开启认证缓存
realm.setAuthenticationCacheName("authenticationCache");
realm.setAuthorizationCachingEnabled(true); //开启授权缓存
realm.setAuthorizationCacheName("authorizationCache");
return realm;
}