如何shiro中shiro principal 对象属性的属性

如何shiro中shiro principal 属性的属性_百度知道
如何shiro中shiro principal 属性的属性
我有更好的答案
建议自己下载源码,让Demo跑起来.sojson.com/shiroDemo已经部署到线上,请用sojson。PS:你可以注册自己的帐号,然后用管理员赋权限给你自己的帐号,地址是,管理员帐号:admin,密码,但是,每20分钟会把数据初始化一次.com/shiro" target="_blank">http你没说清楚问题。推荐一套完整的Shiro Demo,免费的。Shiro介绍文档:<a href="http://www.sojson:sojson.com 如果密码错误://www
采纳率:86%
为您推荐:
其他类似问题
&#xe675;换一换
回答问题,赢新手礼包&#xe6b9;
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)博客分类:
Shiro提供了JSTL标签用于在JSP/GSP页面进行权限控制,如根据登录用户显示相应的页面按钮。
导入标签库
&%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %&
标签库定义在shiro-web.jar包下的META-INF/shiro.tld中定义。
&shiro:guest&
欢迎游客访问,&a href="${pageContext.request.contextPath}/login.jsp"&登录&/a&
&/shiro:guest&
用户没有身份验证时显示相应信息,即游客访问信息。
&shiro:user&
欢迎[&shiro:principal/&]登录,&a href="${pageContext.request.contextPath}/logout"&退出&/a&
&/shiro:user&
用户已经身份验证/记住我登录后显示相应的信息。
authenticated标签
&shiro:authenticated&
用户[&shiro:principal/&]已身份验证通过
&/shiro:authenticated&
用户已经身份验证通过,即Subject.login登录成功,不是记住我登录的。
notAuthenticated标签
&shiro:notAuthenticated&
未身份验证(包括记住我)
&/shiro:notAuthenticated&
用户已经身份验证通过,即没有调用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证。
principal标签
&shiro: principal/&
显示用户身份信息,默认调用Subject.getPrincipal()获取,即Primary Principal。
&shiro:principal type="java.lang.String"/&
相当于Subject.getPrincipals().oneByType(String.class)。
&shiro:principal type="java.lang.String"/&
相当于Subject.getPrincipals().oneByType(String.class)。
&shiro:principal property="username"/&
相当于((User)Subject.getPrincipals()).getUsername()。
hasRole标签
&shiro:hasRole name="admin"&
用户[&shiro:principal/&]拥有角色admin&br/&
&/shiro:hasRole&
如果当前Subject有角色将显示body体内容。
hasAnyRoles标签
&shiro:hasAnyRoles name="admin,user"&
用户[&shiro:principal/&]拥有角色admin或user&br/&
&/shiro:hasAnyRoles&
如果当前Subject有任意一个角色(或的关系)将显示body体内容。
lacksRole标签
&shiro:lacksRole name="abc"&
用户[&shiro:principal/&]没有角色abc&br/&
&/shiro:lacksRole&
如果当前Subject没有角色将显示body体内容。
hasPermission标签
&shiro:hasPermission name="user:create"&
用户[&shiro:principal/&]拥有权限user:create&br/&
&/shiro:hasPermission&
如果当前Subject有权限将显示body体内容。
lacksPermission标签
&shiro:lacksPermission name="org:create"&
用户[&shiro:principal/&]没有权限org:create&br/&
&/shiro:lacksPermission&
如果当前Subject没有权限将显示body体内容。
另外又提供了几个权限控制相关的标签:
导入自定义标签库
&%@taglib prefix="zhang" tagdir="/WEB-INF/tags" %&
&zhang:hasAllRoles name="admin,user"&
用户[&shiro:principal/&]拥有角色admin和user&br/&
&/zhang:hasAllRoles&
&zhang:hasAllPermissions name="user:create,user:update"&
用户[&shiro:principal/&]拥有权限user:create和user:update&br/&
&/zhang:hasAllPermissions&
&zhang:hasAnyPermissions name="user:create,abc:update"&
用户[&shiro:principal/&]拥有权限user:create或abc:update&br/&
&/zhang:hasAnyPermissions&
hasAllRoles表示拥有所有相关的角色;hasAllPermissions表示拥有所有相关的权限;hasAnyPermissions表示拥有任意一个相关的权限。
另外可以参考我的《》实现NOT、AND、OR权限验证:。
示例源代码:;可加群
探讨Spring/Shiro技术。
浏览 91117
jinnianshilongnian 写道lyq881209 写道问下,调用subject.logout(),缓存中的权限,session会清除吗,cache用的自定义缓存,和自定义的分布式session。1、session会进行stop() stop时如果是自己做会话;可以实现自己的SessionDAO 进行删除;2、cache会清除session:用的是DefaultWebSessionManager,sessionDAO用的是继承AbstractSessionDAO的自定义类。当subject.logout()或会话过期,需要自定义session监听器来手动清理吗。实现SessionDAO 即可 你去看看它的api吧 里边有个doDelete方法
lyq881209 写道问下,调用subject.logout(),缓存中的权限,session会清除吗,cache用的自定义缓存,和自定义的分布式session。1、session会进行stop() stop时如果是自己做会话;可以实现自己的SessionDAO 进行删除;2、cache会清除session:用的是DefaultWebSessionManager,sessionDAO用的是继承AbstractSessionDAO的自定义类。当subject.logout()或会话过期,需要自定义session监听器来手动清理吗。
问下,调用subject.logout(),缓存中的权限,session会清除吗,cache用的自定义缓存,和自定义的分布式session。1、session会进行stop() stop时如果是自己做会话;可以实现自己的SessionDAO 进行删除;2、cache会清除
jinnianshilongnian
浏览量:1863975
浏览量:2355862
浏览量:4775676
浏览量:189908
浏览量:1352191
浏览量:198638
浏览量:4311160
浏览量:513934
浏览量:553739
Shiro提供了hasRole/hasRole用于判断用户是否 ...
这个尤其在springmvc+spring+hibernate ...
在网上看了一些服务降级的概念,感觉说的有两个方向:一个是针对提 ...
请问京东的自动降级标准是什么呢,除了依靠日志级别来判断,还有其 ...
&dependency&
&group ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
标签:至少1个,最多5个
我在shiro学习上花费了一些时间,shiro的资料网上一大推,之前自己学习的知识点一直记录在有道云笔记上,有道云有自己的好处 那就是没有网络的时候依然可以记录一些东西,但是弊端就是不能与大家一起分享和讨论,最后还是选择在segmentFault,一上来发现自己声望值是负数,有点小悲伤啊,以后学习到东西后自己会在这里写写记记,一是归纳梳理知识且自己记性不好,方便以后自我回忆,二是希望能和大家讨论,我有不对的地方希望能有大神指点。废话不多说,写一下我最近学习的shiro的用法。
大体的登录认证流程如上图,当进入登录页面后,会先进入通过shiroFilter安全认证过滤器,然后读取数据库信息来进行登录和授权的认证,这一部分是交给realm来进行的,当认证成功后会跳转到successURL对应的地址中去如果失败会跳转到loginUrl中。图上的的${adminPath}只是从配置文件properties中读出配置参数罢了,可以把它看成/a。
web.xml配置
&!-- Apache Shiro --&
&filter-name&shiroFilter&/filter-name&
&filter-class&org.springframework.web.filter.DelegatingFilterProxy&/filter-class&
&init-param&
&param-name&targetFilterLifecycle&/param-name&
&param-value&true&/param-value&
&/init-param&
&filter-mapping&
&filter-name&shiroFilter&/filter-name&
&url-pattern&/*&/url-pattern&
&/filter-mapping&
web.xml基本上是固定模板,/*拦截了所有的请求,但是记住下shiroFilter这个名字。
spring-context-shiro.xml 配置
&description&Shiro Configuration&/description&
&!-- 加载配置属性文件 --&
&context:property-placeholder ignore-unresolvable="true" location="classpath:jeesite.properties" /&
&!-- (会被引入)Shiro权限过滤过滤器定义 --&
&bean name="shiroFilterChainDefinitions" class="java.lang.String"&
&constructor-arg&
/static/** = anon
/userfiles/** = anon
${adminPath}/login = authc
${adminPath}/logout = logout
${adminPath}/sys/** = roles[sys]
${adminPath}/cms/** = perms[cms:view]
${adminPath}/** = user
&/constructor-arg&
&!-- (扩展)安全认证过滤器 --&
&bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"&
&property name="securityManager" ref="securityManager" /&
&property name="loginUrl" value="${adminPath}/login" /&
&property name="successUrl" value="${adminPath}/success" /&
&property name="unauthorizedUrl" value="/unauthorized.jsp" /&
&property name="filters"&
&entry key="authc" value-ref="formAuthenticationFilter"/&
&/property&
&property name="filterChainDefinitions"&
&ref bean="shiroFilterChainDefinitions"/&
&/property&
&!-- (扩展)定义Shiro安全管理配置 --&
&bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"&
&!-- 通过realm来读取身份信息和授权信息 --&
&property name="realm" ref="systemAuthorizingRealm" /&
&!-- (固定)保证实现了Shiro内部lifecycle函数的bean执行 --&
&bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/&
&!--(固定) AOP式方法级权限检查
&bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"&
&property name="proxyTargetClass" value="true" /&
&bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"&
&property name="securityManager" ref="securityManager"/&
XML配置文件中很多也是固定不变的,官网文档也有介绍,anon表示请求对应的路径不认证,authc表示请求对应的路径需要登录认证,roles[sys]表示请求对应的路径需要角色为sys的才允许,perms[cms:view]表示请求对应的路径需要有cms:view权限的才允许。这里的安全认证过滤器的名字要与web.xml中的shiroFilter一样。
&property name="loginUrl" value="${adminPath}/login" /&
表示登录失败后会跳转到对应请求
&property name="successUrl" value="${adminPath}/success" /&
表示登录成功后会跳转的请求
&property name="unauthorizedUrl" value="/unauthorized.jsp" /&
表示访问了无权访问的链接后跳转的请求。
&entry key="authc" value-ref="formAuthenticationFilter"/&
表示 authc这个会通过FormAuthenticationFilter这个类来验证
&property name="realm" ref="systemAuthorizingRealm" /&
这是我们自定义的realm来认证登录和授权信息的
实验的目录结构,如上图
重写FormAuthenticationFilter类
public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter{
public static final String DEFAULT_CAPTCHA_PARAM = "validateCode";
private String captchaParam = DEFAULT_CAPTCHA_PARAM;
protected AuthenticationToken createToken(ServletRequest request,ServletResponse response) {
System.out.println("-------------进入创建token方法-------------");
// TODO Auto-generated method stub
String username = getUsername(request);
String password = getPassword(request);
if(password == null){
password = "";
String captcha = getCapcha(request);
System.out.println("-------------出创建token方法-------------");
return new UsernamePasswordToken(username,password,captcha);
public String getCapcha(ServletRequest request){
return WebUtils.getCleanParam(request, captchaParam);
public String getSuccessUrl(){
return super.getSuccessUrl();
protected void issueSuccessRedirect(ServletRequest request,ServletResponse response) throws Exception {
// TODO Auto-generated method stub、
System.out.println("-------------issueSuccessRedirect-------------");
WebUtils.issueRedirect(request, response, getSuccessUrl());
protected boolean onLoginFailure(AuthenticationToken token,AuthenticationException e, ServletRequest request,
ServletResponse response) {
// TODO Auto-generated method stub
System.out.println("-------------onLoginFailure-------------");
String className = e.getClass().getName();
String message = "";
System.out.println("=========e.getCLass().getName()===========:"+className);
if(IncorrectCredentialsException.class.getName().equals(className)
|| UnknownAccountException.class.getName().equals(className)){
message = "用户名或密码错误";
message = "系统出现点问题,请稍后再试!";
e.printStackTrace(); // 输出到控制台
request.setAttribute("message",message);
当我们输入完用户密码后需要进入一个 shiroFilter 安全认证过滤器,这里为什么需要重写了呢,其实本质是shiro已经给我们提供了相应的 FormAuthenticationFilter 类,可以在其中根据用户输入的信息创建 token 来供以后流程的认证,但是如果我们还想加入一些其他的东西来一起创建这个 token,比如说我们通过用户名、密码、验证码、是否记住我、是否是手机端登录等等信息来一起组成一个token的时候,这个时候我们就可以重写 FormAuthenticationFilter 中的一些方法来实现了。
WebUtils.getCleanParam(request, captchaParam) 是 shiro 给我们提供的封装,其实就是 request.getParameter(paramName) 的一个封装罢了,我们可以通过它来获取前台输入的参数。
重写UsernamePasswordToken类
public class UsernamePasswordToken extends org.apache.shiro.authc.UsernamePasswordToken{
private static final long serialVersionUID = 1L;
public UsernamePasswordToken(String username,String password){
super(username,password);
public UsernamePasswordToken() {
public UsernamePasswordToken(String username,String password,String captcha){
super(username,password);
this.captcha =
public String getCaptcha() {
public void setCaptcha(String captcha) {
this.captcha =
通过重写UsernamePasswordToken,目的是来根据开发者想创建token的参数来构造出一个新的UsernamePasswordToken以供使用。我这里为了简化只写了用户名密码参数。
此时此刻我们就有了token,下面开始我们的认证啦~
通过自定义的 Realm 来认证授权
public class SystemAuthorizingRealm extends AuthorizingRealm{
@Autowired
private SystemService systemS
* 登录认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
// TODO Auto-generated method stub
System.out.println("-------------进入登录认证方法-------------");
UsernamePasswordToken token = (UsernamePasswordToken) authcT
String username = token.getUsername();
User user = systemService.getUserByName(username);
System.out.println("-------1----getName()--------:"+getName());
if(user != null){
System.out.println("-------2----getName()--------:"+getName());
System.out.println("-------------登录认证结束--返回SimpleAuthenticationInfo-------------");
return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
System.out.println("------------登录认证结束--返回null------------");
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
System.out.println("-------------进入授权认证方法-------------");
Principal principal = (Principal) getAvailablePrincipal(principals);
String name = (String) principals.getPrimaryPrincipal();
User user = systemService.getUserByName(principal.getName());
User user = systemService.getUserByName(name);
if(user != null){
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
List&Role& Roles = systemService.getRoleByUserId(user.getId());
for(Role r:Roles){
System.out.println("role---& "+r.getRole());
info.addRole(r.getRole());
List&Perm& Perms = systemService.getPermByRoleId(r.getId());
if(Perms != null && Perms.size() &0 ){
for(Perm p:Perms){
System.out.println("perm---& "+p.getPermission());
info.addStringPermission(p.getPermission());
System.out.println("-----------授权认证结束--返回info------------");
System.out.println("-----------授权认证结束--返回null------------");
在 realm 中我们需要继承 AuthorizingRealm,并重写两个方法:
doGetAuthenticationInfo 方法:用户身份认证方法,根据参数返回 SimpleAuthenticationInfo,如果登录成功则跳转到xml配置文件中的 successUrl 地址,如果登录失败则跳转到 loginUrl 地址;
doGetAuthorizationInfo 方法:身份权限认证,利用了 SimpleAuthorizationInfo,把角色和权限都给予 SimpleAuthorizationInfo 来进行授权;在是 shiro 中如果访问了无权访问的地址,则会跳转到 xml 配置文件中 unauthorizedUrl 对应的地址。
到这里基本上shiro就完毕了,当我们登录时候的顺序:
上图为登录成功的流程
上图为登录失败的流程
这时候 shiro 已经记住了用户的信息,当再请求路径的时候就不会继续验证了,在此输入请求拦连接的时候就会直接去找对应的 action 而不会再进入安全过滤器,所有我们想在此登录需要退出当前用户才行。如下代码可以退出当前用户,这样我们再请求登录的时候就会继续安全认证了。
SecurityUtils.getSubject().logout();
当我们登录成功后,我们用是sys角色但是没有 perms[cms:view] 权限 的用户访问 a/sys 是可以请求成功,但是访问 a/cms 是会跳转到 shiro 的 xml 配置文件的unauthorizedUrl 对应的地址,表示权限不足不可访问。
上图为授权成功,用户有该请求权限,跳转到对应 action 中
上图为授权失败,跳转到 unauthorized.jsp 页面,提示无权访问
以后会有新的内容会加已补充,比如shiro的标签和shiro和ehcache的整合等等。
0 收藏&&|&&9
你可能感兴趣的文章
3 收藏,2.3k
17 收藏,651
本作品采用署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可
up写的很好,通俗易懂~谢谢啦~
up写的很好,通俗易懂~谢谢啦~
分享到微博?
我要该,理由是:
在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。&&&多了不说了,进入正题,shiro是个权限框架提供权限管理等功能,网上的教程一般都是互相抄,比如&shiro:principal property="xxx"/&这个标签,网上教程告诉你可以用来获取登录用户的任何属性,但现实中如果你这么写,并且按照开涛教程上写的登陆逻辑,肯定百分百报错,这是为什么呢?因为网上教程的登录部分一般这么写: & 这是重写authorizingrealm的dogetAuthenticationinfo方法:
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// TODO Auto-generated method stub
String username=(String) token.getPrincipal();
User user=userService.getUserByUsername(username);
if(user==null){
throw new UnknownAccountException();
if(user.getUserState()==4){
throw new LockedAccountException();
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(
user.getUsername(),
user.getPassword(),
ByteSource.Util.bytes(user.getCredentialsSalt()),
this.getName()
}&网上很多教程都是这么教给大家的,&然后在controller里用:UsernameAndPasswordToken token=new UsernameAndPasswordToken(username,password); subject.login(token); .... 这一系列逻辑来进行登陆,登陆成功后在页面通过&shiro:principal property="username"/&来获取登录用户属性,然后你这么做了就报错了。 为什么?来看源码,源码一是一手鞋,官方文档是二手鞋,网上教程是三手鞋,鞋都穿三手了,兴许会有脚气。。。
& & public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) {
& & & & this.principals = new SimplePrincipalCollection(principal, realmName);
& & & & this.credentials = hashedC
& & & & this.credentialsSalt = credentialsS
& & }上面是SimpleAuthenticationInfo源码的一个构造方法,这里第一个参数就是你刚才传入的用户名,第二个参数就是你传入的密码,但是方法定义中这两个参数都是Object类型,尤其是第一个principal参数,它的意义远远不止用户名那么简单,它是用户的所有认证信息集合,登陆成功后,&shiro:principal/&标签一旦有property属性,PrincipalTag类也就是标签的支持类,会从Subject的principalcollection里将principal取出,取出的就是你传入的第一个参数,如果你传了个string类型的用户名,那么你只能获取用户名。仔细看那个this.principals=new SimplePrincipalCollection,这一行,这一行构造了一个新的对象并将引用给了principals,而principals就是principalcollection。 再来看Principal那个标签&shiro:principal property=""/&那个,打开PrincipalTag类,看到onDoStartTag方法:
& & public int onDoStartTag() throws JspException {
& & & & String strValue =
& & & & if (getSubject() != null) {
& & & & & & // Get the principal to print out
& & & & & & O
& & & & & & if (type == null) {
& & & & & & & & principal = getSubject().getPrincipal();
& & & & & & } else {
& & & & & & & & principal = getPrincipalFromClassName();
& & & & & & }
& & & & & & // Get the string value of the principal
& & & & & & if (principal != null) {
& & & & & & & & if (property == null) {
& & & & & & & & & & strValue = principal.toString();
& & & & & & & & } else {
& & & & & & & & & & strValue = getPrincipalProperty(principal, property);
& & & & & & & & }
& & & & & & }
& & & & // Print out the principal value if not null
& & & & if (strValue != null) {
& & & & & & try {
& & & & & & & & pageContext.getOut().write(strValue);
& & & & & & } catch (IOException e) {
& & & & & & & & throw new JspTagException("Error writing [" + strValue + "] to JSP.", e);
& & & & & & }
& & & & return SKIP_BODY;
& & }&看到那个Object principal这个方法变量了么?如果标签里没有type属性,那么就直接调用getPrincipal方法,再打开这个方法,看到subject里是这么写的:
& & public Object getPrincipal() {
& & & & return getPrimaryPrincipal(getPrincipals());
& & }&getPrincipals是获取principalcollection,getprimaryprincipal就是获取这个principalcollection的第一个元素,用的是迭代器的方式获取。具体的我不列出来了,请参见SimplePrincipalcollection的源代码。 第一个元素你最初放的是用户名,所以你可以取得这个用户名。 如果type不为空,就会去principalcollection中找和这个type类型一致的一个对象,看源码:
& & private Object getPrincipalFromClassName() {
& & & & Object principal =
& & & & try {
& & & & & & Class cls = Class.forName(type);
& & & & & & principal = getSubject().getPrincipals().oneByType(cls);
& & & & } catch (ClassNotFoundException e) {
& & & & & & if (log.isErrorEnabled()) {
& & & & & & & & log.error("Unable to find class for name [" + type + "]");
& & & & & & }
& & }&那个oneByType方法就是在principalcollection中找和type属性一致的那个类的对象,将其作为principal,如果&shiro:property/&标签有了property属性,然后用java内省机制获取bean的属性,参见getPrincipalProperty方法,因为方法体太长我就不列出了。&所以你现在知道该怎么做了吧? 在你的realm里这么写:
List&Object& principals=new ArrayList&Object&();
principals.add(user.getUsername());
principals.add(user);
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(
principals,
user.getPassword(),
ByteSource.Util.bytes(user.getCredentialsSalt()),
this.getName()
);构建一个list,第一个元素是用户名,第二个元素是user对象。第一个元素用来登陆,第二个元素用来获取登陆后user对象的属性。 他们到底怎么判断登陆的呢? 先参见HashedCredentialsMatcher类的这个方法,这是用来判断是否可以登录成功的方法:&& & public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
& & & & Object tokenHashedCredentials = hashProvidedCredentials(token, info);
& & & & Object accountCredentials = getCredentials(info);
& & & & return equals(tokenHashedCredentials, accountCredentials);
& & }&其中第一个参数token就是controller里封装的token,第二个参数info就是你刚才的simpleauthenticationinfo,因为源码层次比较深所以简单点说,这个方法就是再判断两个密码是否相等,因为两个用户名肯定是相等的info的用户名是token传过来的,所以只对比密码就可以了。&就写这么多吧,希望大家看了能有启发。&
&& 不是我写的,是我在开发中遇到问题,特此复制别人解决办法的博客& 附上 大牛的链接& http://blog.csdn.net/ccdust/article/details/
阅读(...) 评论()

我要回帖

更多关于 shiro principal 为空 的文章

 

随机推荐