关于shiro的学习推荐官网:
链接地址: http://shiro.apache.org/
前言:
Shiro 是 Java 的一个安全框架。目前,使用 Apache Shiro 的人越来越多,因为它相当简单,对比 SpringSecurity,可能没有 Spring Security 做的功能强大,但是在实际工作时我们可能并不需要那么复杂的东西,所以使用小而简单的Shiro 就足够了。
一、ACL和RBAC
- ACL: Access Control List
访问控制列表 以前盛行的一种权限设计,它的核心在于用户直接和权限挂钩
优点:简单易用,开发便捷 缺点:用户和权限直接挂钩,导致在授予时的复杂性,比较分散,不便于管理 例子:常见的文件系统权限设计, 直接给用户加权限 - RBAC: Role Based Access Control
基于角色的访问控制系统。权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限
优点:简化了用户与权限的管理,通过对用户进行分类,使得角色与权限关联起来 缺点:开发对比ACL相对复杂
例子:基于RBAC模型的权限验证框架与应用 Apache Shiro、spring Security BAT企业
ACL,一般是对报表系统,阿里的ODPS
二、shiro中的一些基础概念和专业名词(重要)
1、基础概念:
什么是身份认证?
Authentication,身份证认证,一般就是登录
什么是授权?
Authorization,给用户分配角色或者访问某些资源的权限
什么是会话管理?
Session Management, 用户的会话管理员,多数情况下是web session
什么是加密?
Cryptography, 数据加解密,比如密码加解密等
什么是主体(subject)?
主体,可以看到主体可以是任何可以与应用交互的“用户”;
2、shiro实现原理流程图解:
在这个流程里面,我们可以看到API 核心就是 Subject,其中各个部分的解释与作用——
- Subject:主体,代表了当前 “用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject 都绑定到SecurityManager,与 Subject 的所有交互都会委托给 SecurityManager;可以把Subject 认为是一个门面;SecurityManager才是实际的执行者;
- SecurityManager:安全管理器;即所有与安全有关的操作都会与 SecurityManager 交互;且它管理着所有Subject;可以看出它是 Shiro 的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet 前端控制器;
- Realm:域,Shiro 从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager
要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 /权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource,即安全数据源。
如果我们写一个最简单的Shiro应用,那么大概流程应该是——
应用代码通过 Subject 来进行认证和授权,而 Subject 又委托给 SecurityManager;我们需要给 Shiro 的 SecurityManager 注入 Realm,从而让 SecurityManager 能得到合法的用户及其权限进行判断。
3、架构图;
4、框架专业名词解读
Subject
我们把用户或者程序称为主体(如用户,第三方服务,cron作业),主体去访问系统或者资源
SecurityManager
安全管理器,Subject的认证和授权都要在安全管理器下进行
Authenticator
认证器,主要负责Subject的认证
Cache Manager
缓存管理器,比如认证或授权信息,通过缓存进行管理,提高性能
Session Manager
会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通 JavaSE 环境的,也可以是如 Web 环境的;
Realm
数据域,Shiro和安全数据的连接器,好比jdbc连接数据库; 通过realm获取认证授权相关信息
Authorizer
授权器,主要负责Subject的授权, 控制subject拥有的角色或者权限
Cryptography
加解密,Shiro的包含易于使用和理解的数据加解密方法,简化了很多复杂的api
Concurrency
shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
SessionDAO
DAO 大家都用过,数据访问对象,用于会话的 CRUD,比如我们想把 Session 保存到数据库,那么可以实现自己的 SessionDAO,通过如 JDBC 写到数据库;比如想把 Session 放到 Memcached 中,可以实现自己的 Memcached SessionDAO;另外 SessionDAO 中可以使用 Cache 进行缓存,以提高性能;
5、安全数据源realm
5.1、shiro自带的默认的realm
- realm作用:Shiro 从 Realm 获取安全数据
默认自带的realm:idae查看realm继承关系,有默认实现和自定义继承的realm 两个概念 - principal : 主体的标示,可以有多个,但是需要具有唯一性,常见的有用户名,手机号,邮箱等 credential:凭证, 一般就是密码 所以一般我们说 principal + credential 就账号 + 密码 开发中,往往是自定义realm , 即集成 AuthorizingRealm
5.2、shiro数据源使用.ini配置文件
ini配置文件内容:
# 格式 name=password,role1,role2,..roleN
[users]
# user 'root' with password 'secret' and the 'admin' role,
jack = 456, user
# user 'guest' with the password 'guest' and the 'guest' role
xdcalss = 123, root
# 格式 role=permission1,permission2...permissionN 也可以用通配符
# 下面配置user的权限为所有video:find,video:buy,如果需要配置video全部操作crud 则 user = video:*
[roles]
user = video:find,video:buy
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
快速启动测试
@Test
public void test(){
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
//设置token 模拟用户输入账号密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","456");
subject.login(usernamePasswordToken);
System.out.println(subject.isAuthenticated());
subject.hasRole("admin");
System.out.println(subject.getPrincipal());
}
5.3、shiro数据源realm使用jdbc方式注入
a、使用jdbc.ini文件
#注意 文件格式必须为ini,编码为ANSI
#声明Realm,指定realm类型
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
#配置数据源
#dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
dataSource=com.alibaba.druid.pool.DruidDataSource
# mysql-connector-java 5 用的驱动url是com.mysql.jdbc.Driver,mysql-connector-java6以后用的是 com.mysql.cj.jdbc.Driver
dataSource.driverClassName=com.mysql.cj.jdbc.Driver
#避免安全警告
dataSource.url=jdbc:mysql://localhost:3306/myshiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
dataSource.username=wyy
dataSource.password=xxx
#指定数据源
jdbcRealm.dataSource=$dataSource
#开启查找权限, 默认是false,不会去查找角色对应的权限,坑!!!!!
jdbcRealm.permissionsLookupEnabled=true
#指定SecurityManager的Realms实现,设置realms,可以有多个,用逗号隔开
securityManager.realms=$jdbcRealm
快速启动
@Test
public void test2(){
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:jdbcrealm.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
//设置token 模拟用户输入账号密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","123");
subject.login(usernamePasswordToken);
System.out.println(subject.isAuthenticated());
subject.hasRole("admin");
System.out.println(subject.getPrincipal());
}
b、使用Java配置值类
@Test
public void test1(){
DefaultSecurityManager securityManager = new DefaultSecurityManager();
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/myshiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false");
ds.setUsername("wyy");
ds.setPassword("xxx");
JdbcRealm jdbcRealm = new JdbcRealm();
jdbcRealm.setPermissionsLookupEnabled(true);
jdbcRealm.setDataSource(ds);
securityManager.setRealm(jdbcRealm);
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
//设置token 模拟用户输入账号密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","123");
subject.login(usernamePasswordToken);
System.out.println(subject.isAuthenticated());
subject.hasRole("admin");
System.out.println(subject.getPrincipal());
}
三、整合boot快速启动
导入shiro依赖:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
这里使用的是shiro内置的realm
/**
* @author wyy
* @version 1.0
* @date 2020/3/27 10:11
* @description
**/
public class QuickStart_shiro {
private SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
private DefaultSecurityManager securityManager = new DefaultSecurityManager();
@Before
public void init(){
//添加账户
simpleAccountRealm.addAccount("zhangsan","123");
//设置realm 构建 环境
securityManager.setRealm(simpleAccountRealm);
}
@Test
public void test(){
//设置上下文
SecurityUtils.setSecurityManager(securityManager);
//当前操作主体
Subject subject = SecurityUtils.getSubject();
//设置token 模拟用户输入账号密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("zhangsan","1234");
subject.login(usernamePasswordToken);
Boolean isAccess = subject.isAuthenticated();
System.out.println(isAccess);
}
}
四、shiro自定义realm(重要)
步骤:
- 创建一个AuthorizingRealm类 ,
- 继承树AuthorizingRealm->AuthenticatingRealm->CachingRealm->Realm
- 重写授权方法 doGetAuthorizationInfo
- 重写认证方法 doGetAuthenticationInfo
1、重写方法介绍:
- 当用户登陆的时候会调用 doGetAuthenticationInfo
- 进行权限校验的时候会调用: doGetAuthorizationInfo
2、一些被用到的对象介绍:
UsernamePasswordToken : 对应就是 shiro的token中有Principal和Credential
继承树:
UsernamePasswordToken-》HostAuthenticationToken-》AuthenticationToken
SimpleAuthorizationInfo:代表用户角色权限信息
SimpleAuthenticationInfo :代表该用户的认证信息
3、自定义realm
/**
* @author wyy
* @version 1.0
* @date 2020/4/7 14:38
* @description
**/
public class CustomRealm extends AuthorizingRealm {
//创建模拟用户
private final Map<String,String> userInfoMap = new HashMap<>();
{
userInfoMap.put("jack","123");
userInfoMap.put("admin","123");
}
//创建模拟权限
private final Map<String,Set<String>> permissionMap = new HashMap<>();
{
Set<String> set1 = new HashSet<>();
Set<String> set2 = new HashSet<>();
set1.add("video:find");
set1.add("video:buy");
set2.add("video:add");
permissionMap.put("jack",set1);
permissionMap.put("admin",set2);
}
//创建模拟角色
private final Map<String,Set<String>> roleMap = new HashMap<>();
{
Set<String> set1 = new HashSet<>();
Set<String> set2 = new HashSet<>();
set1.add("role1");
set1.add("role2");
set2.add("root");
roleMap.put("jack",set1);
roleMap.put("admin",set2);
}
//进行权限校验的时候会调用: doGetAuthorizationInfo
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("权限:doGetAuthorizationInfo");
String name = (String)principalCollection.getPrimaryPrincipal();
Set<String> permission = getPermissionsFromDB(name);
Set<String> roles = getRolesByNameFromDB(name);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addRoles(roles);
simpleAuthorizationInfo.addStringPermissions(permission);
return simpleAuthorizationInfo;
}
private Set<String> getRolesByNameFromDB(String name) {
return roleMap.get(name);
}
private Set<String> getPermissionsFromDB(String name) {
return permissionMap.get(name);
}
//当用户登陆的时候会调用 doGetAuthenticationInfo
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("认证:doGetAuthenticationInfo");
String name = (String)authenticationToken.getPrincipal();
String pwd = getPwdByNameFromDB(name);
if(null == pwd || "".equals(pwd)){
return null;
}
//pwd 可能需要一个加盐操作
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name,pwd,this.getName());
return simpleAuthenticationInfo;
}
private String getPwdByNameFromDB(String name) {
return userInfoMap.get(name);
}
}
4、自定义realm实例化
/**
* @author wyy
* @version 1.0
* @date 2020/4/7 14:39
* @description
**/
public class QuickStart_shiro2 {
private CustomRealm simpleAccountRealm = new CustomRealm();
private DefaultSecurityManager securityManager = new DefaultSecurityManager();
@Before
public void init(){
//设置realm 构建 环境
securityManager.setRealm(simpleAccountRealm);
//设置上下文
SecurityUtils.setSecurityManager(securityManager);
}
@Test
public void test(){
//当前操作主体
Subject subject = SecurityUtils.getSubject();
//设置token 模拟用户输入账号密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","123");
subject.login(usernamePasswordToken);
Boolean isAccess = subject.isAuthenticated();
subject.checkPermission("video:find");
subject.checkPermission("video:buy");
subject.hasRole("root");
System.out.println(isAccess);
}
}
五、shiro内置过滤器Fileter讲解(重要)
1、DefaultFilter 及其内部的枚举类
ssl :org.apache.shiro.web.filter.authz.SslFilter
user :org.apache.shiro.web.filter.authz.UserFilter
anon :org.apache.shiro.web.filter.authc.AnonymousFilter
port :org.apache.shiro.web.filter.authz.PortFilter
rest :org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
authc :org.apache.shiro.web.filter.authc.FormAuthenticationFilter
perms :org.apache.shiro.web.filter.authz.PermissionAuthorizationFilter
roles :org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
logout :org.apache.shiro.web.filter.authc.LogoutFilter
authcBasic :org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
noSessionCreation :org.apache.shiro.web.filter.session.NoSessionCreationFilter
是不是感觉一头雾水 别急下面列出对应功能
//匿名访问 游客访问路径
filterChainDefinitionMap.put("/pub/**", "anon");
//退出过滤器
filterChainDefinitionMap.put("/user/logout", "logout");
//登录用户才能访问
filterChainDefinitionMap.put("/author/**", "authc");
filterChainDefinitionMap.put("/author/**", "authcBasic");
//只有admin管理员才能访问
filterChainDefinitionMap.put("/admin/**", "roles[admin]");
//只有视频修改权限的才能访问
filterChainDefinitionMap.put("/goods/video/update", "perms[video_update]");
//authc : url 必须通过认证才能访问
//anon : url可以匿名访问
filterChainDefinitionMap.put("/**", "authc");
port:org.apache.shiro.web.filter.authz.PortFilter
端口拦截器, 可通过的端口。
ssl:org.apache.shiro.web.filter.authz.SslFilter
ssl拦截器,只有请求协议是https才能通过
这些过滤器分为两组,一组是认证过滤器,一组是授权过滤器。
- anon,authcBasic,auchc,user是第一组,
- perms,roles,ssl,rest,port是第二组
权限校验的两种方式
shiro权限控制注解和编程方式讲解
1、注解方式
@RequiresRoles(value={"admin", "editor"}, logical= Logical.AND)
需要角色 admin 和 editor两个角色 AND表示两个同时成立
@RequiresPermissions (value={"user:add", "user:del"}, logical= Logical.OR)
需要权限 user:add 或 user:del权限其中一个,OR是或的意思。
@RequiresAuthentication
已经授过权,调用Subject.isAuthenticated()返回true
@RequiresUser
身份验证或者通过记 住我登录的
2、编码形式
Subject subject = SecurityUtils.getSubject();
//基于角色判断
if(subject.hasRole(“admin”)) {
//有角色,有权限
} else {
//无角色,无权限
}
//或者权限判断
if(subject.isPermitted("/user/add")){
//有权限
}else{
//无权限
}
2、shiroFilterFactoryBean配置编写(非常重要)
1、配置流程与思路
- shirofilterfactorybean -》securitymanager
- customsessionmanager
- customrealm ->HashedCredentialsmatcher
- sessionmanager
- defaultsessionmanager :默认实现常用于JavaSE
- servletcontainersessionmanager :web环境
- defaultwebsessionmanager:常用于自定义实现
2、过滤器shiroFilterFactoryBean的实现 Java配置类的书写
/**
* @author wyy
* @version 1.0
* @Classname ShiroConfig
* @date 2020/4/16 10:56
* @description
**/
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
System.out.println("ShiroFilterFactoryBean.shiroFilter() 执行了");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//这里设置了登录接口 如果访问了某个接口没有登录 就会调用这个接口(如果不是前后端分离就返回页面)
shiroFilterFactoryBean.setLoginUrl("/pub/need_login");
//如果是前后端分离则不需要这个
//shiroFilterFactoryBean.setSuccessUrl();
//这个是用户登录了 但没有权限 就会调用这个接口
shiroFilterFactoryBean.setUnauthorizedUrl("/pub/need_permission");
/**
*拦截器路径 坑1:部分路径无法拦截,拦截效果时有时无,因为使用了hashMap 是无序的应该使用linkedHashMap
*原因在于过滤链执行顺序是顺序执行所以需要使用有序的linkedHashMap
**/
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//匿名访问 游客访问路径
filterChainDefinitionMap.put("/pub/**", "anon");
//退出过滤器
filterChainDefinitionMap.put("/user/logout", "logout");
//登录用户才能访问
filterChainDefinitionMap.put("/author/**", "authc");
//只有管理员才能访问
filterChainDefinitionMap.put("/admin/**", "roles[admin]");
//视频修改权限
filterChainDefinitionMap.put("/goods/video/update","perms[video_update]");
//坑2:过滤链是顺序执行的,从上而下,一般来讲/** 是放到最下面的
//authc : url 必须通过认证才能访问
//anon : url可以匿名访问
filterChainDefinitionMap.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(customRealm());
securityManager.setSessionManager(sessionManager());
return securityManager;
}
//自定义realm注入
@Bean
public CustomRealm customRealm() {
CustomRealm customRealm = new CustomRealm();
customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return customRealm;
}
//自定义sessionmanager注入
@Bean
public SessionManager sessionManager() {
//使用自定义sessionmanager 具体写法看 六—3
CustomSessionManager customSessionManager = new CustomSessionManager();
return customSessionManager;
}
//加密方式
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
//设置散列算法 :这里设置的MD5
credentialsMatcher.setHashAlgorithmName("MD5");
//设置多重加密算法 :这里设置的是2次加密(mad5(md5(xxx)))
credentialsMatcher.setHashIterations(2);
return credentialsMatcher;
}
}
六、shiro缓存模块
1、什么是会话session?
用户与程序的链接,程序可以根据session来区分不同的用户。
2、什么是会话管理器 sessionmanager?
会话管理器管理所有的subject的操作,是shiro的核心
核心方法:
//开启一个session
Session start(SessionContext context);
//指定Key获取session
Session getSession(SessionKey key)
shiro中的会话管理器有多个实现
SessionDao 会话存储/持久化
SessionDAO AbstractSessionDAO CachingSessionDAO EnterpriseCacheSessionDAO MemorySessionDAO
核心方法
//创建
Serializable create(Session session);
//获取
Session readSession(Serializable sessionId) throws UnknownSessionException;
//更新
void update(Session session)
//删除,会话过期时会调用
void delete(Session session);
//获取活跃的session
Collection<Session> getActiveSessions();
3、自定义sessionManager验证
/**
* @author wyy
* @version 1.0
* @Classname CustomSessionManager
* @date 2020/4/16 13:35
* @description
**/
public class CustomSessionManager extends DefaultWebSessionManager {
private final static String AUTHORIZATION = "token";
public CustomSessionManager(){
super();
}
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
String sessionId = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
if(null != sessionId ){
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return sessionId;
}else{
return super.getSessionId(request,response);
}
}
}
七、api验证
/**
* @author wyy
* @version 1.0
* @Classname PublicController
* @date 2020/4/20 10:03
* @description
**/
@RestController
@RequestMapping(name = "公共接口",value = "/pub")
public class PublicController {
@RequestMapping(name = "设置的未登录拦截接口",value = "/need_login")
public JsonData needLogin(){
return JsonData.buildSuccess(-2,"请先登录");
}
@RequestMapping(name = "设置登录但未授权的用户拦截接口",value = "/need_permission")
public JsonData needPermission(){
return JsonData.buildSuccess(-3,"您没有权限,请联系管理员!");
}
@RequestMapping(name = "初始化界面",value = "/index")
public JsonData index(){
List<String> goods = new ArrayList<>();
goods.add("空调");
goods.add("水壶");
goods.add("电冰箱");
goods.add("热水器");
goods.add("烤箱");
return JsonData.buildSuccess(goods);
}
@RequestMapping(name = "登录",value = "login")
public JsonData login(@RequestBody UserBO userBO, HttpServletRequest request, HttpServletResponse response){
Subject subject = SecurityUtils.getSubject();
Map<String,Object> map = new HashMap<>(16);
try {
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userBO.getName(), userBO.getPwd());
subject.login(usernamePasswordToken);
map.put("token",subject.getSession().getId());
}catch (Exception e){
map.put("msg","账号或密码不存在!");
}
return JsonData.buildSuccess(map);
}
}
1、游客访问接口:不需要登录就可以访问
@RestController
@RequestMapping(value = "author")
public class OrderController {
@RequestMapping(value = "listOrder")
public JsonData ListOrder(){
Map<String,String> map = new HashMap<>(16);
map.put("springboot基础","19.00元");
map.put("redis基础","29.00元");
map.put("activeMq基础","13.00元");
return JsonData.buildSuccess(map);
}
}
2、author:需要用户登录才能访问接口
@RestController
@RequestMapping(value = "/goods/video")
public class VideoController {
@RequestMapping(value = "update")
public JsonData videoUpdate(){
return JsonData.buildSuccess();
}
}
3、需要有video_update 权限的用户才能访问
这里只有Jack有更新权限所以John是没有权限访问该接口的
/**
* @author wyy
* @version 1.0
* @date 2020/4/14 9:46
* @description
**/
@RestController
@RequestMapping(name = "用户模块", value = "admin")
public class UserController {
@RequestMapping(name = "根据id获取角色所有权限",value = "/getPermissionById")
public List<Role> getRoles(@RequestParam(value = "id") Integer id){
return userService.getRoles(id);
}
}
4、注意点:
4.1、登录时,我们输入的是明文,但是realm使用了一层MD5加密,所以你的数据库里存储的密码应该要是密文才能校验通过,否则就会出现下面错误
当然上面的登录例子里面进行了try catch 操作所以不会抛错
4.2、登录获取的token并非永久,如果不设置过期时间shiro默认30分钟,这里我们在sessionmanager里面配置了session过期时间18s
4.3、前端传的凭证名称是由后端sessionmanager规定