用户登录的详细流程(三)Shiro框架
Shiro框架是一个功能强大的java安全框架,执行身份验证,授权,加密和会话处理。
**
1.核心架构
Authentication (认证):用户身份认证-----登录
Authorization(授权):访问控制----权限
Session Management(会话管理):会话管理
Cryptography(加密):加密Subject:主体,外部应用与subject进行交互,subject记录了当前的操作用户,将用户的概念理解为主体。外部程序通过subject进行认证授权,而subject通过Security Manager 安全管理器进行认证授权。
Security Manager :安全管理器,对全部的subject进行安全管理,它是Shiro的核心,通过它可以完成subject的认证和授权。实质上它是通过Authentication进行认证,通过Authorization进行授权的,通过Session Management 进行会话管理。
Authentication:认证器,是一个接口。
Authorization:授权器,用户通过了认证器的判断之后,在判断是否有操作权限。
realm:领域 安全管理器进行认证要通过realm类来获取用户数据,realm中可以有认证和授权相关代码。
**
2.如何实现自定义realm
**
public class Realm extends AuthorizingRealm
只要继承了AuthorizingRealm 就可以同时实现认证和授权的功能。
**
3.实现代码
**
public class Realm extends AuthorizingRealm {
@Override
//必须写,不写就报错
public boolean supports(AuthenticationToken token) {
return token instanceof userToken;
}
//只有使用@RequiresPermissions 注解才会调用其中的授权和认证方法
/**
* 授权(验证权限时调用)
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection collection) {
User user= (User)collection.getPrimaryPrincipal();//获得当前用户对象
Long userId = user.getId();//获取用户id
Set<String> permSet = accountService.getUserPermission(userId);//获取当前的权限列表,这里用的是mapper层的方法直接返回具体的权限代码
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 把权限列表添加到info对象中
info.setStringPermissions(permSet);
return info;
}
/**
* 认证(验证登录时调用)
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String accessToken = (String) token.getPrincipal();//通过方法进行获取token
Long userId= jwtUtil.getUserIdFromToken(accessToken);//通过自定义的jwtUtil里面的方法去进行获取对应的userId
/**
* 接下来根据获得的用户信息进行判断用户是否可以用
*/
// 往info对象中添加用户信息、Token字符串
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user
, accessToken, getName());
return info;
**
4.ShiroConfig (Shiro的配置,拦截器的使用)
**
@Configuration
public class ShiroConfig {
@Bean("securityManager")
public SecurityManager securityManager(OAuth2Realm oAuth2Realm) {
//将自定义配置的realm加载入系统,从而替换系统自带的realm类
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(Realm);
// 服务端不保存凭证
securityManager.setRememberMeManager(null);
return securityManager;
}
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(oAuth2Realm);
// 服务端不保存凭证
securityManager.setRememberMeManager(null);
return securityManager;
}
@Bean("shiroFilter")//注入
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager, Filter UserFilter) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
Map<String, Filter> filters = new HashMap<>();//定义拦截器
filters.put("user", UserFilter);//讲自定义的拦截器放入拦截器集合中
shiroFilter.setFilters(filters);//将集合放入拦截器的系统中
// anon 为不拦截的路径(这是系统定义的)
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/auth/login", "anon");
// 所有请求都需要user验证
filterMap.put("/**", "user");
shiroFilter.setFilterChainDefinitionMap(filterMap);//将路径放入系统中,等待spring的自动处理。
return shiroFilter;
}
}
**
5.自定义拦截器
**
public class user extends AuthenticatingFilter {
//其中有两个重要的方法,这些方法的执行人事spring自己
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
//里面进行判断逻辑,返回布尔值
//return true 直接调回controller层,反之进入下面的方法onAccessDenied()
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
//里面写一些验证token的代码,如果通过就进入controller 否则返回错误代码。
}
}
**
6.Shiro权限的使用
**
(1)@RequiresPermissions(value = {“权限名1”, “权限名2”}, logical = Logical.AND)
表示必须符合全部权限才能进入下面的方法
(2)@RequiresPermissions(value = {“权限名1”, “权限名2”}, logical = Logical.OR)
表示符合一个就可以了。
这里的注释会按照顺序进行调用自己写的realm中的认证方法doGetAuthenticationInfo()和权限认证方法doGetAuthorizationInfo()