shiro是什么
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。(百度百科)
主要功能
三个核心组件:Subject, SecurityManager 和 Realms.
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。 Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。 SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。 Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。 从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。 Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
springboot+shiro的dome
maven依赖
<!-- Apache Shiro版本号
-->
<properties>
<project
.build
.sourceEncoding
>UTF
-8</project
.build
.sourceEncoding
>
<project
.reporting
.outputEncoding
>UTF
-8</project
.reporting
.outputEncoding
>
<java.version>1.8</java
.version
>
<shiro.version>1.4.0</shiro
.version
>
<shiro
-redis
.version
>3.1.0</shiro
-redis
.version
>
</properties
>
<!-- Apache Shiro依赖
-->
<dependency>
<groupId>org
.apache
.shiro
</groupId
>
<artifactId>shiro
-spring
</artifactId
>
<version>1.4.0</version
>
</dependency
>
<dependency>
<groupId>org
.apache
.shiro
</groupId
>
<artifactId>shiro
-core
</artifactId
>
<version>$
{shiro
.version
}</version
>
</dependency
>
<dependency>
<groupId>org
.apache
.shiro
</groupId
>
<artifactId>shiro
-ehcache
</artifactId
>
<version>$
{shiro
.version
}</version
>
</dependency
>
<dependency>
<groupId>org
.crazycake
</groupId
>
<artifactId>shiro
-redis
</artifactId
>
<version>$
{shiro
-redis
.version
}</version
>
</dependency
>
shiro配置类
package com
.fc
.test
.system
.config
;
import java
.util
.Collection
;
import java
.util
.LinkedHashMap
;
import java
.util
.Map
;
import javax
.servlet
.Filter
;
import com
.fc
.test
.common
.constant
.ConstantConfig
;
import com
.fc
.test
.system
.shiro
.StatelessDefaultSubjectFactory
;
import com
.fc
.test
.system
.shiro
.auth
.AuthRealm
;
import com
.fc
.test
.system
.shiro
.filter
.AuthenticationFilter
;
import com
.fc
.test
.system
.shiro
.filter
.JcaptchaValidateFilter
;
import com
.fc
.test
.system
.shiro
.session
.ShiroSessionManager
;
import org
.apache
.shiro
.SecurityUtils
;
import org
.apache
.shiro
.mgt
.DefaultSecurityManager
;
import org
.apache
.shiro
.session
.mgt
.SessionManager
;
import org
.apache
.shiro
.spring
.LifecycleBeanPostProcessor
;
import org
.apache
.shiro
.spring
.security
.interceptor
.AuthorizationAttributeSourceAdvisor
;
import org
.apache
.shiro
.spring
.web
.ShiroFilterFactoryBean
;
import org
.apache
.shiro
.web
.mgt
.DefaultWebSecurityManager
;
import org
.apache
.shiro
.web
.mgt
.DefaultWebSubjectFactory
;
import org
.apache
.shiro
.web
.servlet
.SimpleCookie
;
import org
.crazycake
.shiro
.RedisCacheManager
;
import org
.crazycake
.shiro
.RedisManager
;
import org
.crazycake
.shiro
.RedisSessionDAO
;
import org
.springframework
.aop
.framework
.autoproxy
.DefaultAdvisorAutoProxyCreator
;
import org
.springframework
.boot
.web
.servlet
.FilterRegistrationBean
;
import org
.springframework
.context
.annotation
.Bean
;
import org
.springframework
.context
.annotation
.Configuration
;
import org
.springframework
.context
.annotation
.DependsOn
;
import org
.springframework
.web
.filter
.DelegatingFilterProxy
;
@Configuration
public class ShiroConfig {
@Bean
public AuthRealm
myShiroRealm() {
AuthRealm authRealm
= new AuthRealm();
return authRealm
;
}
@Bean
public FilterRegistrationBean
<DelegatingFilterProxy> delegatingFilterProxy() {
FilterRegistrationBean
<DelegatingFilterProxy> filterRegistrationBean
= new FilterRegistrationBean<>();
DelegatingFilterProxy proxy
= new DelegatingFilterProxy();
proxy
.setTargetFilterLifecycle(true);
proxy
.setTargetBeanName("shiroFilter");
filterRegistrationBean
.setFilter(proxy
);
filterRegistrationBean
.setOrder(2);
return filterRegistrationBean
;
}
@Bean("shiroFilter")
@DependsOn("securityManager")
public ShiroFilterFactoryBean
shiroFilter(DefaultSecurityManager securityManager
) {
ShiroFilterFactoryBean shiroFilter
= new ShiroFilterFactoryBean();
shiroFilter
.setSecurityManager(securityManager
);
Map
<String, String> filterChainDefinitionMap
= new LinkedHashMap<>();
filterChainDefinitionMap
.put("/api/v1/login", "anon");
filterChainDefinitionMap
.put("/api/v1/reg", "anon");
filterChainDefinitionMap
.put("/druid/**", "anon");
filterChainDefinitionMap
.put("/api-docs", "anon");
filterChainDefinitionMap
.put("/v2/api-docs", "anon");
filterChainDefinitionMap
.put("/favicon.ico", "anon");
filterChainDefinitionMap
.put("/swagger-ui.html", "anon");
filterChainDefinitionMap
.put("/webjars/**", "anon");
filterChainDefinitionMap
.put("/swagger-resources/**", "anon");
filterChainDefinitionMap
.put("/static/**", "anon");
shiroFilter
.setFilterChainDefinitionMap(filterChainDefinitionMap
);
return shiroFilter
;
}
@Bean
public DefaultWebSubjectFactory
subjectFactory() {
return new StatelessDefaultSubjectFactory();
}
@Bean
public AuthorizationAttributeSourceAdvisor
authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor
= new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor
.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor
;
}
@Bean("securityManager")
public DefaultWebSecurityManager
securityManager() {
DefaultWebSecurityManager securityManager
= new DefaultWebSecurityManager();
securityManager
.setRealm(myShiroRealm());
SecurityUtils
.setSecurityManager(securityManager
);
return securityManager
;
}
@Bean
public SessionManager
sessionManager() {
SimpleCookie simpleCookie
= new SimpleCookie("Token");
simpleCookie
.setPath("/");
simpleCookie
.setHttpOnly(false);
ShiroSessionManager sessionManager
= new ShiroSessionManager();
sessionManager
.setSessionDAO(redisSessionDAO());
sessionManager
.setSessionIdCookieEnabled(false);
sessionManager
.setSessionIdUrlRewritingEnabled(false);
sessionManager
.setDeleteInvalidSessions(true);
sessionManager
.setSessionIdCookie(simpleCookie
);
return sessionManager
;
}
@Bean
public RedisSessionDAO
redisSessionDAO() {
RedisSessionDAO redisSessionDAO
= new RedisSessionDAO();
redisSessionDAO
.setRedisManager(redisManager());
return redisSessionDAO
;
}
@Bean(name
= "lifecycleBeanPostProcessor")
public static LifecycleBeanPostProcessor
lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator
advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator
= new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator
.setProxyTargetClass(true);
return advisorAutoProxyCreator
;
}
@Bean
public RedisCacheManager
cacheManager() {
RedisCacheManager redisCacheManager
= new RedisCacheManager();
redisCacheManager
.setRedisManager(redisManager());
return redisCacheManager
;
}
public RedisManager
redisManager() {
RedisManager redisManager
= new RedisManager();
redisManager
.setHost(ConstantConfig
.springRedisHost
);
redisManager
.setPort(ConstantConfig
.springRedisPort
);
redisManager
.setTimeout(1800);
redisManager
.setPassword(ConstantConfig
.springRedisPassword
);
return redisManager
;
}
}
自定义Realm认证授权
package com
.fc
.test
.system
.shiro
.auth
;
import lombok
.extern
.slf4j
.Slf4j
;
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
;
@Slf4j
public class AuthRealm extends AuthorizingRealm {
public AuthRealm() {}
@Override
protected AuthorizationInfo
doGetAuthorizationInfo(PrincipalCollection principals
) {
log
.info("=============shiro权限授权=============");
String username
= String
.valueOf(principals
);
Set
<String> roles
= new HashSet<>();
Set
<String> permissions
= new HashSet<>();
if("user".equals(username
)){
roles
.add("user");
permissions
.add("user:detail");
}
if ("admin".equals(username
)) {
roles
.add("admin");
permissions
.add("admin:add");
permissions
.add("admin:detele");
permissions
.add("admin:detail");
permissions
.add("admin:list");
permissions
.add("admin:update");
}
SimpleAuthorizationInfo info
= new SimpleAuthorizationInfo(roles
);
info
.setStringPermissions(permissions
);
info
.setRoles(roles
);
return info
;
}
@Override
protected AuthenticationInfo
doGetAuthenticationInfo(AuthenticationToken authenticationToken
)
throws AuthenticationException
{
log
.info("=============shiro开始认证=============");
UsernamePasswordToken upToken
= (UsernamePasswordToken
) authenticationToken
;
String username
= upToken
.getUsername();
Condition condition
= new Condition(TSysUser
.class);
condition
.createCriteria().andEqualTo("username",username
);
List
<TSysUser> tSysUserList
= tSysUserMapper
.selectByCondition(condition
);
if(tSysUserList
==null
|| tSysUserList
.isEmpty()){
throw new UnknownAccountException();
}
TSysUser tSysUser
= tSysUserList
.get(0);
return new SimpleAuthenticationInfo(username
,tSysUser
.getPassword(), getName());
}
@Override
public void clearCachedAuthorizationInfo(PrincipalCollection principals
) {
super.clearCachedAuthorizationInfo(principals
);
}
@Override
public void clearCachedAuthenticationInfo(PrincipalCollection principals
) {
super.clearCachedAuthenticationInfo(principals
);
}
@Override
public void clearCache(PrincipalCollection principals
) {
super.clearCache(principals
);
}
private void clearAllCachedAuthorizationInfo() {
getAuthorizationCache().clear();
}
private void clearAllCachedAuthenticationInfo() {
getAuthenticationCache().clear();
}
public void clearAllCache() {
clearAllCachedAuthenticationInfo();
clearAllCachedAuthorizationInfo();
}
}
控制层shiro认证
package com
.fc
.test
.controller
.user
;
import com
.fc
.test
.util
.CommonUtil
;
import io
.swagger
.annotations
.Api
;
import io
.swagger
.annotations
.ApiOperation
;
import io
.swagger
.annotations
.ApiResponse
;
import io
.swagger
.annotations
.ApiResponses
;
import lombok
.extern
.slf4j
.Slf4j
;
import org
.apache
.shiro
.SecurityUtils
;
import org
.apache
.shiro
.authc
.UsernamePasswordToken
;
import org
.apache
.shiro
.subject
.Subject
;
import org
.springframework
.web
.bind
.annotation
.PostMapping
;
import org
.springframework
.web
.bind
.annotation
.RequestMapping
;
import org
.springframework
.web
.bind
.annotation
.RestController
;
@Slf4j
@Api(value
= "用户登录", tags
= {"用户登录"})
@RestController
@RequestMapping("/api/v1")
public class LoginControllet {
@ApiOperation(value
= "登录", notes
= "请注意请求参数!")
@ApiResponses({
@ApiResponse(code
= 200, message
= "成功", response
= String
.class),
@ApiResponse(code
= 999, message
= "失败"),
})
@PostMapping("/login")
public String
userLogin(String userName
,String passWord
) {
String pwd
= CommonUtil
.encryptMD5(userName
+passWord
);
UsernamePasswordToken usernamePasswordToken
= new UsernamePasswordToken(userName
,pwd
);
String token
= CommonUtil
.generateToken();
Subject subject
= SecurityUtils
.getSubject();
subject
.login(usernamePasswordToken
);
return token
;
}
}
控制层shiro授权过程
@ApiOperation(value
= "获取数据列表")
@ApiResponses({
@ApiResponse(code
= 200, message
= "成功", response
= TSysUser
.class),
@ApiResponse(code
= 101, message
= "数据校验未通过"),
@ApiResponse(code
= 999, message
= "失败"),
@ApiResponse(code
= 1501, message
= "用户令牌过期"),
})
@ApiImplicitParams({
@ApiImplicitParam(name
= "page", value
= "页数 "),
@ApiImplicitParam(name
= "size", value
= "每页数量 "),
})
@GetMapping
@RequiresPermissions("admin:list")
public RestResponse
list(@RequestParam(defaultValue
= "1") Integer page
, @RequestParam(defaultValue
= "10") Integer size
) {
PageInfo pageInfo
= tSysUserService
.findTSysUserList(page
, size
);
return RestResponse
.builder().respStatus(RespStatus
.SUCCESS
).respData(pageInfo
).build();
}
代码执行
登录 这里正确账号密码是账号:admin 密码:123456 输入正确账号密码返回token shiro进行认证,账号密码跟数据库一致认证成功 输出错误账号或密码,接口返回的自定义异常是根据shiro抛出的异常自己自定义的 shiro进行授权验证 admin账号有查询列表的权限请求成功 user账号进行登录查询用户列表 这就是shiro整个认证授予过程 数据库密码是使用用户名+密码md5加密组成