将 Shiro 作为应用的权限基础 三:基于注解实现的授权认证过程
授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限。
如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限等等。
一、用户权限模型
为实现一个较为灵活的用户权限数据模型,通常把用户信息单独用一个实体表示,用户权限信息用两个实体表示。
用户信息用LoginAccount 表示,最简单的用户信息可能只包含用户名loginName 及密码password 两个属性。
实际应用中可能会包含用户是否被禁用,用户信息是否过期等信息。
用户权限信息用Role 与Permission 表示,Role 与Permission 之间构成多对多关系。
Permission 可以理解为对一个资源的操作,Role 可以简单理解为Permission 的集合。
用户信息与Role 之间构成多对多关系。
表示同一个用户可以拥有多个Role,一个Role 可以被多个用户所拥有。
权限声明及粒度
Shiro权限声明通常是使用以冒号分隔的表达式。
就像前文所讲,一个权限表达式可以清晰的指定资源类型,允许的操作。
同时,Shiro权限表达式支持简单的通配符,可以更加灵活的进行权限设置。
下面以实例来说明权限表达式。
可查询用户数据
User:view
可查询或编辑用户数据
User:view,edit
可对用户数据进行所有操作
User:*或user
可编辑id为123的用户数据
User:edit:123
授权处理过程
认证通过后接受Shiro 授权检查,授权验证时,需要判断当前角色是否拥有该权限。
只有授权通过,才可以访问受保护URL 对应的资源,否则跳转到“未经授权页面”。
如果我们自定义Realm实现,比如我后面的例子中,自定义了ShiroDbRealm类,当访问被@RequiresPermissions注解的方法时,会先执行ShiroDbRealm.doGetAuthorizationInfo()进行授权。
二、授权实现
Shiro支持三种方式实现授权过程:
o编码实现
o注解实现
o JSP Taglig实现
1、基于编码的授权实现
1、基于权限对象的实现
创建org.apache.shiro.authz.Permission的实例,将该实例对象作为参数传递给Subject.isPermitted()进行验证。
使用冒号分隔的权限表达式是org.apache.shiro.authz.permission. WildcardPermission默认支持的实现方式。
这里分别代表了资源类型:操作:资源ID
2、基于注解的授权实现
3、基于JSP TAG的授权实现
Shiro提供了一套JSP标签库来实现页面级的授权控制。
在使用Shiro 标签库前,首先需要在JSP引入shiro标签:
三、Shiro授权的内部处理机制
1、在应用程序中调用授权验证方法(Subject的isPermitted*或hasRole*等)
2、Sbuject会委托应用程序设置的securityManager实例调用相应的isPermitted*或hasRole*方法。
3、接下来SecurityManager会委托内置的Authorizer的实例(默认是ModularRealmAuthorizer类的实例,类似认证实例)调用相应的授权方法。
4、每一个Realm将检查是否实现了相同的Authorizer 接口。
然后,将调用Reaml自己的相应的授权验证方法。
ShiroDbRealm:自定义的指定Shiro验证用户授权的类。
Shiro权限管理框架(一):Shiro的基本使用
Shiro权限管理框架(⼀):Shiro的基本使⽤shiro概念:Apache Shiro是⼀个强⼤且易⽤的Java安全框架,执⾏⾝份验证、授权、密码和会话管理。
使⽤Shiro的易于理解的API,您可以快速、轻松地获得任何应⽤程序,从最⼩的移动应⽤程序到最⼤的⽹络和企业应⽤程序。
上⾯这段话来⾃百度百科,没啥⽤。
想要快速理解并使⽤Shiro要先从最重要的三⼤概念⼊⼿。
1. Subject:⼤⽩话来讲就是⽤户(当然并不⼀定是⽤户,也可以指和当前应⽤交互的任何对象),我们在进⾏授权鉴权的所有操作都是围绕Subject(⽤户)展开的,在当前应⽤的任何地⽅都可以通过SecurityUtils的静态⽅法getSubject()轻松的拿到当前认证(登录)的⽤户。
2. SecurityManager:安全管理器,Shiro中最核⼼的组件,它管理着当前应⽤中所有的安全操作,包括Subject(⽤户),我们围绕Subject展开的所有操作都需要与SecurityManager进⾏交互。
可以理解为SpringMVC中的前端控制器。
3. Realms:字⾯意思为领域,Shiro在进⾏权限操作时,需要从Realms中获取安全数据,也就是⽤户以及⽤户的⾓⾊和权限。
配置Shiro,我们⾄少需要配置⼀个Realms,⽤于⽤户的认证和授权。
通常我们的⾓⾊及权限信息都是存放在数据库中,所以Realms也可以算是⼀个权限相关的Dao层,SecurityManager在进⾏鉴权时会从Realms中获取权限信息。
这三个基本的概念简答理解后就可以开始配置和使⽤Shiro了,其实Shiro最基本的使⽤⾮常简单,加⼊依赖后只需要配置两个Bean,再继承⼀个抽象类实现两个⽅法即可。
基本使⽤:引⼊⼀个依赖新建⼀个基于Springboot的Web项⽬,引⼊Shiro依赖。
<!-- https:///artifact/org.apache.shiro/shiro-web --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.4.0</version></dependency>配置两个Bean新建⼀个Shiro配置类,配置Shiro最为核⼼的安全管理器SecurityManager。
getauthenticationinfo方法详解
getauthenticationinfo方法详解getAuthenticationInfo方法是在Shiro框架中的一种身份认证信息获取方法,通常用于验证用户的身份信息,包括用户名和密码。
该方法的详细解析如下。
1.方法签名:getAuthenticationInfo(AuthenticationToken token):根据用户身份信息,返回身份验证信息。
2.方法参数:- AuthenticationToken token:用户提供的身份信息,通常包括用户名和密码。
3.方法返回值:- AuthenticationInfo对象:表示用户的身份验证信息,包括用户名、密码、盐等信息。
4.方法执行流程:(1) 根据token中的用户名获取数据库中保存的用户信息。
(2) 如果查询结果为空,抛出UnknownAccountException异常,表示用户不存在。
(3)根据查询结果的密码和盐值生成用户的加密密码。
(4) 创建SimpleAuthenticationInfo对象,将用户名、加密密码和盐值等信息存储到对象中。
(5) 返回SimpleAuthenticationInfo对象作为认证信息。
5.相关类及方法介绍:- AuthenticationToken:Shiro中用于存储用户身份信息的接口,通常是由UsernamePasswordToken实现类实现。
- UnknownAccountException:表示未知账户异常,当用户不存在时抛出。
- SimpleAuthenticationInfo:身份验证信息的实现类,用于存储用户的用户名、加密密码和盐值等信息。
- CredentialsMatcher:用于验证用户输入的密码与数据库中保存的密码是否匹配。
- HashedCredentialsMatcher:用于在验证密码时对用户输入的密码进行加密。
6.示例代码:```javapublic class CustomRealm extends AuthorizingRealm//省略其他方法...protected AuthenticationInfogetAuthenticationInfo(AuthenticationToken token) throws AuthenticationExceptionString username = (String) token.getPrincipal(;//根据用户名查询数据库获取用户信息User user = userService.findByUsername(username);if (user == null)throw new UnknownAccountException("用户不存在");}//使用盐值加密用户密码String salt = user.getSalt(;String password = user.getPassword(;String encryptedPassword =encryptionService.encryptPassword(password, salt);//创建身份验证信息对象SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, encryptedPassword, ByteSource.Util.bytes(salt), getName();return authenticationInfo;}}```7.注意事项:- 在调用getAuthenticationInfo方法之前,通常需要先进行身份信息的认证,即调用Authenticator进行身份验证。
shiro学习笔记-Subject#login(token)实现过程
shiro学习笔记-Subject#login(token)实现过程追踪Subject的login(AuthenticationToken token)⽅法,其调⽤的为DelegatingSubject类的login⽅法,DelegatingSubject实现了Subject接⼝,DelegatingSubject#login如下:1public void login(AuthenticationToken token) throws AuthenticationException {2 clearRunAsIdentitiesInternal();3 Subject subject = securityManager.login(this, token);45 PrincipalCollection principals;67 String host = null;89if (subject instanceof DelegatingSubject) {10 DelegatingSubject delegating = (DelegatingSubject) subject;11//we have to do this in case there are assumed identities - we don't want to lose the 'real' principals:12 principals = delegating.principals;13 host = delegating.host;14 } else {15 principals = subject.getPrincipals();16 }1718if (principals == null || principals.isEmpty()) {19 String msg = "Principals returned from securityManager.login( token ) returned a null or " +20 "empty value. This value must be non null and populated with one or more elements.";21throw new IllegalStateException(msg);22 }23this.principals = principals;24this.authenticated = true;25if (token instanceof HostAuthenticationToken) {26 host = ((HostAuthenticationToken) token).getHost();27 }28if (host != null) {29this.host = host;30 }31 Session session = subject.getSession(false);32if (session != null) {33this.session = decorate(session);34 } else {35this.session = null;36 }37 }在上⾯代码的第三⾏:Subject subject = securityManager.login(this, token); 注意到其调⽤了SecurityManager的login⽅法,SecurityManager为接⼝,实际上调⽤的其实现类DefaultSecurityManager的login⽅法,⽅法如下:1public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {2 AuthenticationInfo info;3try {4 info = authenticate(token);5 } catch (AuthenticationException ae) {6try {7 onFailedLogin(token, ae, subject);8 } catch (Exception e) {9if (log.isInfoEnabled()) {10 ("onFailedLogin method threw an " +11 "exception. Logging and propagating original AuthenticationException.", e);12 }13 }14throw ae; //propagate15 }1617 Subject loggedIn = createSubject(token, info, subject);1819 onSuccessfulLogin(token, info, loggedIn);2021return loggedIn;22 }在上⾯代码第四⾏:info = authenticate(token); 继续跟踪,发现authenticate(AuthenticationToken token);⽅法为DefaultSecurityManager的⽗类AuthenticatingSecurityManager的⽅法,AuthenticatingSecurityManager#authenticate⽅法如下:1public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {2return this.authenticator.authenticate(token);3 }authenticator为Authenticator接⼝,继续跟踪,AbstractAuthenticator抽象类实现了Authenticator接⼝,接下来继续查看AbstractAuthenticator#authenticate(token);⽅法:1public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {23if (token == null) {4throw new IllegalArgumentException("Method argument (authentication token) cannot be null.");5 }67 log.trace("Authentication attempt received for token [{}]", token);89 AuthenticationInfo info;10try {11 info = doAuthenticate(token);12if (info == null) {13 String msg = "No account information found for authentication token [" + token + "] by this " +14 "Authenticator instance. Please check that it is configured correctly.";15throw new AuthenticationException(msg);16 }17 } catch (Throwable t) {18 AuthenticationException ae = null;19if (t instanceof AuthenticationException) {20 ae = (AuthenticationException) t;21 }22if (ae == null) {23//Exception thrown was not an expected AuthenticationException. Therefore it is probably a little more24//severe or unexpected. So, wrap in an AuthenticationException, log to warn, and propagate:25 String msg = "Authentication failed for token submission [" + token + "]. Possible unexpected " +26 "error? (Typical or expected login exceptions should extend from AuthenticationException).";27 ae = new AuthenticationException(msg, t);28if (log.isWarnEnabled())29 log.warn(msg, t);30 }31try {32 notifyFailure(token, ae);33 } catch (Throwable t2) {34if (log.isWarnEnabled()) {35 String msg = "Unable to send notification for failed authentication attempt - listener error?. " +36 "Please check your AuthenticationListener implementation(s). Logging sending exception " +37 "and propagating original AuthenticationException instead...";38 log.warn(msg, t2);39 }40 }41throw ae;42 }4344 log.debug("Authentication successful for token [{}]. Returned account [{}]", token, info);4546 notifySuccess(token, info);4748return info;49 }上⾯代码第11⾏:info = doAuthenticate(token); 这个⽅法为ModularRealmAuthticator类中的⽅法,因为ModularRealmAuthticator继承了AbstractAuthenticator抽象类。
SpringBootShiro权限注解不起作用的解决方法
SpringBootShiro权限注解不起作⽤的解决⽅法⽬录问题如下:解决⽅法如下:最近在学习springboot结合shiro做权限管理时碰到⼀个问题。
问题如下:我在userRealm中的doGetAuthorizationInfo⽅法中给⽤户添加了权限,然后在Controller中写了下⾯的代码。
其中URL为/listArticle的⽅法必须要有article:over权限才能通过。
我在doGetAuthorizationInfo⽅法中给该⽤户添加的权限并没有article:over,但是当前端向该URL发送请求时,@RequiresPermissions注解不起作⽤,listArticle⽅法被执⾏了。
⽽且我在⽅法内部打印isPermitted("article:over")的输出结果为false。
最终通过⽹上查博客,发现是没有开启Shiro的注解⽀持的原因。
@RequiresPermissions("article:over")@RequestMapping(value = "/listArticle", method = RequestMethod.POST)public JSONObject listArticle(@RequestBody JSONObject request){System.out.println("---------isPermitted article:over--------" + SecurityUtils.getSubject().isPermitted("article:over"));CommonTools.paginationConvert(request);int ArticleNum = articleService.getArticleNum();List<JSONObject> list = articleService.listArticle(request.getIntValue("offset"), request.getIntValue("pageRow"));return Result.success(request, list, ArticleNum);}解决⽅法如下:在ShiroConfig中添加如下⼀段代码。
simpleauthenticationinfo方法
simpleauthenticationinfo方法SimpleAuthenticationInfo是Shiro框架中的一个重要方法,用于为用户提供简单认证信息。
通过此方法,我们可以实现用户的身份认证和权限控制,从而保护系统的安全性。
本文将一步一步回答与SimpleAuthenticationInfo方法相关的问题,从而帮助读者理解并使用该方法。
一、什么是SimpleAuthenticationInfo方法?SimpleAuthenticationInfo是Shiro框架中的一个方法,它用于为用户提供简单认证信息。
在Shiro中,认证信息主要包括用户的身份、凭证和盐值。
SimpleAuthenticationInfo方法将这些信息封装到一个对象中,并返回给Shiro进行后续的认证操作。
二、SimpleAuthenticationInfo方法的参数SimpleAuthenticationInfo方法具有三个参数,分别为身份信息、凭证信息和盐值。
下面对这三个参数进行具体介绍:1. 身份信息(principal):用户的唯一标识,通常是用户名或用户ID。
在认证过程中,Shiro会使用用户输入的身份信息与存储在系统中的用户信息进行匹配,以判断用户是否合法。
2. 凭证信息(credentials):用户的密码或其他凭证信息。
在认证过程中,Shiro会将用户输入的凭证信息与存储在系统中的凭证信息进行比较,以验证用户是否拥有访问权限。
3. 盐值(salt):用于对用户的凭证信息进行加密或混淆的随机值。
盐值可以增加用户凭证信息的安全性,防止被破解。
在SimpleAuthenticationInfo方法中,可以将盐值作为第三个参数传入。
三、SimpleAuthenticationInfo方法的返回值SimpleAuthenticationInfo方法的返回值是一个SimpleAuthenticationInfo对象。
shiro验证权限的流程
shiro验证权限的流程以shiro验证权限的流程为标题,下面将详细介绍shiro验证权限的流程。
一、什么是shiro验证权限shiro是一个强大且易于使用的Java安全框架,用于身份验证、授权和加密。
它提供了一个可插拔的架构,使开发者可以轻松地集成shiro到他们的应用程序中,并通过简单的配置来实现身份验证和授权功能。
1. 配置shiro安全管理器:首先,我们需要配置一个shiro安全管理器。
安全管理器是shiro的核心组件,负责协调整个身份验证和授权过程。
我们可以通过编写一个shiro配置文件来配置安全管理器,指定所需的身份验证和授权策略。
2. 编写自定义realm:realm是shiro与应用程序进行交互的接口,负责从应用程序中获取用户的身份信息和权限信息。
我们需要编写一个自定义的realm,实现shiro的Realm接口,并重写其中的方法,以便从数据库或其他存储中获取用户的身份和权限信息。
3. 进行身份验证:一旦配置好安全管理器和自定义realm,我们就可以使用shiro进行身份验证了。
首先,用户提交用户名和密码进行登录,shiro会调用自定义realm中的方法,根据用户名从数据库中获取用户的密码,并与用户输入的密码进行比较。
如果密码匹配成功,说明用户身份验证通过;否则,验证失败。
4. 进行授权验证:身份验证通过后,shiro会根据配置的授权策略,判断用户是否具有访问某个资源的权限。
shiro提供了多种授权策略,如基于角色的授权、基于权限的授权等。
我们可以通过在自定义realm中返回用户的角色和权限信息来进行授权验证。
5. 实现权限控制:一旦用户被授权访问某个资源,我们还可以在代码中进行权限控制,以确保用户只能访问他们被授权的资源。
shiro 提供了一些注解和标签,如@RequiresRoles、@RequiresPermissions等,可以方便地在代码中进行权限控制。
6. 处理无权限访问:如果用户没有被授权访问某个资源,我们可以通过配置shiro的未授权页面,将用户重定向到一个友好的页面,或返回相应的错误信息。
shiro认证流程
shiro认证流程Shiro是一个Java安全框架,用于管理用户认证和授权。
Shiro框架提供了强大的认证和授权功能,可以轻松地集成到Java应用程序中。
下面将介绍Shiro认证的基本流程,包括主体查询、凭证匹配、身份认证、认证结果处理等。
1. 主体查询:认证流程的第一步是查询主体的信息。
主体可以是用户、设备或其他可以进行身份认证的实体。
在Shiro框架中,主体由一个唯一标识符表示,通常是用户名或用户ID。
2. 凭证匹配:一旦确定了要认证的主体,就需要验证其相关的凭证。
凭证可以是密码、指纹、证书等。
在认证之前,Shiro通常将凭证存储在一个Realm中,以便在需要时进行匹配。
Realm是Shiro认证的关键组件,它负责查询用户信息、获取用户凭证等操作。
3. 身份认证:凭证匹配成功后,Shiro会对主体进行身份认证。
身份认证是确认主体的身份是否合法的过程。
在这个步骤中,Shiro通过验证主体的凭证来确保主体的身份与凭证的匹配。
4. 认证结果处理:一旦身份认证成功,Shiro可以选择将认证结果存储在会话管理器中,以便随后的请求可以继续访问已通过身份认证的资源。
此外,还可以通过回调方法、事件监听器等方式处理认证结果。
整个Shiro认证流程可以通过以下步骤来总结:1.查询主体信息2.凭证匹配3.身份认证4.认证结果处理除了上述基本认证流程外,Shiro还提供了许多扩展功能,以满足不同应用场景的需求。
例如,可以通过配置文件进行认证配置,允许多种认证方式,支持单点登录等。
Shiro还提供了可插拔的认证策略,可以根据具体的应用需求进行配置。
例如,可以通过配置决定是将认证结果存储在缓存中还是持久化到数据库中。
总结起来,Shiro认证流程是一个灵活且可扩展的流程。
通过了解Shiro的认证流程,开发人员可以更好地了解Shiro框架的工作原理,并根据具体需求进行配置和定制。
shiro认证时拦截器的isAccessAllowed和onAccessDenied执行流程
shiro认证时拦截器的isAccessAllowed和onAccessDenied执行流程1. 拦截器的isAccessAllowed方法执行流程:首先,当用户请求访问一些资源时,shiro会通过过滤器链将请求传递到拦截器中。
拦截器首先会判断当前用户是否已经通过认证,如果用户已经通过认证,则直接返回true,并允许用户访问资源。
这是因为在认证通过后,shiro会将用户信息保存在Subject对象中,拦截器可以通过该对象获取当前用户的认证信息。
如果用户还未通过认证,则拦截器会进一步判断当前请求是否需要进行认证。
这一步是通过调用Subject对象的isAuthenticated方法来判断的。
如果返回true,则表示当前请求需要进行认证,拦截器会将控制权交给shiro的认证器进行处理,并返回false。
认证器会根据配置的Realm对象进行具体的认证操作,例如验证用户名和密码。
如果返回false,则表示当前请求不需要进行认证,拦截器会直接返回true,并允许用户访问资源。
这种情况通常用于设置一些公开资源,例如网站首页等,不需要进行用户认证。
2. 拦截器的onAccessDenied方法执行流程:当拦截器的isAccessAllowed方法返回false时,表明当前请求需要进行认证。
此时,拦截器会进入onAccessDenied方法的执行流程。
首先,拦截器会获取到当前的Subject对象,并将请求的相对路径保存在session中。
这是为了在用户认证通过后,可以重定向到该请求的页面。
然后,拦截器会判断当前请求是否为POST请求。
如果是POST请求,拦截器会将当前请求的页面路径保存在session中。
这是因为在不同的认证方式下,shiro会分别处理GET请求和POST请求,POST请求一般用于提交用户的认证信息(例如用户名和密码),而GET请求用于显示登录页面。
接下来,拦截器会执行shiro的登录方法,该方法会根据配置的认证器进行具体的认证操作。
springboot集成shiro——使用RequiresPermissions注解无效
springboot集成shiro——使用RequiresPermissions注解无效在集成Shiro框架中,我们可以使用RequiresPermissions注解来标识方法或者类级别的权限控制。
但是在一些情况下,可能会遇到包括RequiresPermissions注解无效的情况。
下面我将详细介绍一些可能导致RequiresPermissions注解无效的原因,并给出相应的解决办法。
1. 配置文件问题:Shiro框架需要一个shiro.ini文件或者shiro.yml文件来读取权限规则。
如果你没有指定这个配置文件,或者文件路径不正确,那么RequiresPermissions注解就会无效。
解决方法是在application.yml文件中添加以下配置:```shiro:config:file: classpath:shiro.ini``````javapublic ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager)ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(;shiroFilter.setSecurityManager(securityManager);// 添加需要进行权限控制的urlMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>(;//...shiroFilter.setFilterChainDefinitionMap(filterChainDefinitio nMap);return shiroFilter;}```3. 自定义Realm问题:如果你使用了自定义的Realm,那么可能是Realm中没有正确配置权限信息导致RequiresPermissions注解无效。
shiro key的识别方法
shiro key的识别方法在web应用程序中,Shiro框架通过Shiro Key提供了一种简单的方式来授权访问。
Shiro Key是一个字符串,用于支持安全操作的授权认证。
Shiro Key的识别方法是由Shiro框架自动完成的,需要我们按照一定的流程来配置和使用Shiro Key。
本文将分步骤阐述Shiro Key的识别方法:1. 创建一个Shiro Key首先,我们需要创建一个Shiro Key,可以使用随机字符串或自定义字符串生成。
例如,使用常量字符串来作为Shiro Key:```javapublic static final String SHIRO_KEY = "myShiroKey";```2. 将Shiro Key添加到应用程序接下来,将Shiro Key添加到应用程序。
通常,我们可以将Shiro Key添加到应用程序的配置文件中。
例如,在web.xml文件中添加下面的参数:```xml<context-param><param-name>shiro.loginUrl</param-name><param-value>/login.jsp</param-value></context-param><context-param><param-name>shiro.successUrl</param-name><param-value>/index.jsp</param-value></context-param><context-param><param-name>shiro.key</param-name><param-value>myShiroKey</param-value></context-param>```3. 配置Shiro过滤器Shiro过滤器是用来控制应用程序的访问权限。
