Shiro
核心组件
UsernamePasswordToken: shiro用来封装用户登录信息,使用用户的登录信息来创建令牌TokenSecurityManager :shiro的核心部分,负责安全认证和授权Subject :Shiro的一个抽象概念,包含了用户信息Realm :开发者自定义的模块,验证和授权的逻辑全部写在Realm中AuthenticationInfo:用户的角色信息集合,认证时使用AuthorzationInfo:用户的权限信息集合,授权时使用DefaultWebSecurityDManager:安全管理器,开发者自定义Realm需要注入到进行管理才能生效ShiroFilterFactoryBean:过滤器工厂
功能简介
Authentication :身份认证/登录
Authorization :授权,权限验证
SessionManagement:会话管理
Cryptography:加密
WebSupport : Web支持
Caching: 缓存
Concurrency: 并发验证
Testing:测试
“Run As”:允许一个用户假装另一个用户
Remember me:记住我
Spring Boot 整合 shiro
认证过滤器
anon:无需认证
autc:必须认证
authBasic:需要通过HttpBasic认证
user:不一定通过认证,只要曾经被shiro记录即可,(记住我)
授权过滤器
perms:必须拥有某个权限
roles:必须拥有某个角色
prot:必须 指定端口
rest:请求必须基于 RestFul
ssl:必须是安全的url请求 ,协议HTTPS
shiro依赖
<dependency>
<groupId>org.apache.shiro
</groupId>
<artifactId>shiro-spring
</artifactId>
<version>1.5.3
</version>
</dependency>
<dependency>
<groupId>org.apache.shiro
</groupId>
<artifactId>shiro-ehcache
</artifactId>
<version>1.2.2
</version>
</dependency>
<dependency>
<groupId>org.springframework.boot
</groupId>
<artifactId>spring-boot-starter-data-redis
</artifactId>
</dependency>
shiro配置类
@Configuration
public class MyShiRo {
@Bean
public UserRealm
userRealm(){
UserRealm userRealm
= new UserRealm();
HashedCredentialsMatcher credentialsMatcher
= new HashedCredentialsMatcher();
credentialsMatcher
.setHashAlgorithmName("MD5");
credentialsMatcher
.setHashIterations(1024);
userRealm
.setCredentialsMatcher(credentialsMatcher
);
userRealm
.setCacheManager(new RedisCacheManager());
userRealm
.setAuthenticationCachingEnabled(true);
userRealm
.setAuthenticationCacheName("authentication");
userRealm
.setAuthorizationCachingEnabled(true);
userRealm
.setAuthorizationCacheName("authorization");
return userRealm
;
}
@Bean
public DefaultWebSecurityManager
defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm
){
DefaultWebSecurityManager manager
=new DefaultWebSecurityManager();
manager
.setRealm(userRealm
);
return manager
;
}
@Bean
public ShiroFilterFactoryBean
shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager
){
ShiroFilterFactoryBean factoryBean
= new ShiroFilterFactoryBean();
factoryBean
.setSecurityManager(defaultWebSecurityManager
);
Map
<String,String> map
=new HashMap<String, String>();
map
.put("/index","authc");
map
.put("/","authc");
map
.put("/vip","perms[manage]");
map
.put("/admin","roles[admin]");
map
.put("/login","anon");
map
.put("/register","anon");
factoryBean
.setFilterChainDefinitionMap(map
);
factoryBean
.setLoginUrl("/login");
factoryBean
.setUnauthorizedUrl("/index");
return factoryBean
;
}
}
shiro-自定义realm
public class UserRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo
doGetAuthorizationInfo(PrincipalCollection principals
) {
Subject subject
= SecurityUtils
.getSubject();
User user
= (User
) subject
.getPrincipal();
Set
<String> set
= new HashSet<>();
set
.add(user
.getRole());
SimpleAuthorizationInfo info
= new SimpleAuthorizationInfo(set
);
info
.addStringPermission(user
.getPerms());
return info
;
}
@Override
protected AuthenticationInfo
doGetAuthenticationInfo(AuthenticationToken authenticationToken
) throws AuthenticationException
{
UsernamePasswordToken token
= (UsernamePasswordToken
) authenticationToken
;
UserServiceImpl userService
= (UserServiceImpl
) SpringUtils
.getBean("userServiceImpl");
User user
= userService
.findUserByName(token
.getUsername());
if(user
!=null
){
return new SimpleAuthenticationInfo(user
,user
.getPassword(), new MyByteSource(user
.getSalt()),this.getName());
}
return null
;
}
}
controller层
@PostMapping("/login")
public String
loginAuthentication(String username
, String password
, Model model
){
Subject subject
= SecurityUtils
.getSubject();
UsernamePasswordToken token
=new UsernamePasswordToken(username
,password
);
try{
subject
.login(token
);
return "redirect:/";
}catch (UnknownAccountException e
){
e
.printStackTrace();
model
.addAttribute("msg","账户错误");
return "login";
}catch (IncorrectCredentialsException e
){
e
.printStackTrace();
model
.addAttribute("msg","密码错误");
return "login";
}
}
加密(MD5)
在shiro配置类 userRealm中加上
HashedCredentialsMatcher credentialsMatcher
= new HashedCredentialsMatcher();
credentialsMatcher
.setHashAlgorithmName("MD5");
credentialsMatcher
.setHashIterations(1024);
userRealm
.setCredentialsMatcher(credentialsMatcher
);
加密方式 Service层
public void register(User user
) {
String salt
= SaltUtils
.getSalt(8);
user
.setSalt(salt
);
Md5Hash md5Hash
= new Md5Hash(user
.getPassword(),salt
,1024);
user
.setPassword(md5Hash
.toHex());
userMapper
.insertUser(user
);
}
salt工具类
public class SaltUtils {
public static String
getSalt(int n
){
char[] chars
= "QWERTYUIOPLKJHGFDSAZXCVBNMqwertyuioplkjhgfdsazxcvbnm1234567890!@#$%^&*".toCharArray();
StringBuilder sb
= new StringBuilder();
for (int i
= 0; i
< n
; i
++) {
char achar
=chars
[new Random().nextInt(chars
.length
)];
sb
.append(achar
);
}
return sb
.toString();
}
}
缓存(EhCache,RedisCache)
依赖
<dependency>
<groupId>org.apache.shiro
</groupId>
<artifactId>shiro-ehcache
</artifactId>
<version>1.2.2
</version>
</dependency>
在shiro配置类 自定义userRealm
userRealm
.setCacheManager(new EhCacheManager());
userRealm
.setAuthenticationCachingEnabled(true);
userRealm
.setAuthenticationCacheName("authentication");
userRealm
.setAuthorizationCachingEnabled(true);
userRealm
.setAuthorizationCacheName("authorization");
Redis缓存
实现shiro缓存底层的cacheManager 和cache 接口
实现cache
public class MyRedis<K,V> implements Cache<K,V> {
public String cacheName
;
public MyRedis() {
}
public MyRedis(String cacheName
) {
this.cacheName
= cacheName
;
}
public RedisTemplate
redisTemplate(){
RedisTemplate redisTemplate
= (RedisTemplate
) SpringUtils
.getBean("redisTemplate");
redisTemplate
.setKeySerializer(new StringRedisSerializer());
return redisTemplate
;
}
@Override
public V
get(K k
) throws CacheException
{
return (V
) redisTemplate().opsForHash().get(this.cacheName
,k
.toString());
}
@Override
public V
put(K k
, V v
) throws CacheException
{
redisTemplate().opsForHash().put(this.cacheName
,k
.toString(),v
);
return null
;
}
@Override
public V
remove(K k
) throws CacheException
{
return (V
) redisTemplate().opsForHash().delete(this.cacheName
,k
.toString());
}
@Override
public void clear() throws CacheException
{
redisTemplate().delete(this.cacheName
);
}
@Override
public int size() {
return redisTemplate().opsForHash().size(this.cacheName
).intValue();
}
@Override
public Set
<K> keys() {
return redisTemplate().opsForHash().keys(this.cacheName
);
}
@Override
public Collection
<V> values() {
return redisTemplate().opsForHash().values(this.cacheName
);
}
}
实现CacheManager
public class RedisCacheManager implements CacheManager {
@Override
public <K, V> Cache
<K, V> getCache(String cacheName
) throws CacheException
{
return new MyRedis<K,V>(cacheName
);
}
}