shiro与spring整合详解与spring项目中shiro注解不生效的解决办法

来源:互联网 发布:北京网页游戏编程培训 编辑:程序博客网 时间:2024/06/05 19:12

一、spring项目中的shiro配置

(1)web.xml配置

<!-- shiro过滤器 --><filter><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><filter-mapping><filter-name>shiroFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

(2)shiro与spring整合配置

<!-- 使用shiro安全检查注解 --><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" /><bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"><property name="securityManager" ref="securityManager" /></bean>

<!-- shiro的生命周期处理器 --><bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /><!-- shiro自带的密码匹配器(用来校验密码足够了) --> <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.SimpleCredentialsMatcher"></bean>  <!-- security datasource: --><bean id="myRealm" class="cc.eguid.service.shiro.MyRealm"><property name="credentialsMatcher" ref="credentialsMatcher"/><!-- 密码匹配器 -->        <property name="cachingEnabled" value="false"/><!-- 禁止缓存 --></bean><!-- 安全管理器 --><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="myRealm" /></bean><!-- shiro过滤器 --><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><!-- 配置安全管理器 --><property name="securityManager" ref="securityManager" /><!-- 身份认证失败跳转的地址 --><property name="loginUrl" value="/login/" /><!-- 身份认证成功跳转的地址 --><property name="successUrl" value="/" /><!-- 权限认证失败跳转的地址 --><property name="unauthorizedUrl" value="/login/unauthorized" /><property name="filterChainDefinitions"><!--anon 表示匿名访问,不需要认证以及授权 --><!--authc表示需要认证 没有进行身份认证是不能进行访问的 --><!--authc,roles[admin]表示是admin角色的用户才能访问 --><value>/static/** = anon/login/** = anon/common/** = anon/admin/** = authc,roles[admin]/* = authc/** = authc</value></property></bean>

二、realm和自定义密码校验器实现

1、realm实现

public class MyRealm extends AuthorizingRealm{Logger log=Logger.getLogger(MyRealm.class);@Autowired    private UserService userService;//这是自己实现的用户信息操作类,实现用户信息,用户角色信息、用户权限信息查询功能@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {UserInfo user = (UserInfo) principals.getPrimaryPrincipal();SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();// 查询角色信息Collection<String> roles = userService.findRoles(user);info.addRoles(roles);log.info("shiro获取用户所属角色列表:"+roles);// 查询权限信息Collection<String> permissions = userService.findPermissions(user.getSystemuserid());info.addStringPermissions(permissions);log.info("shiro获取用户权限列表:"+permissions);return info;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)throws AuthenticationException{//用户输入的用户名密码String loginname=  token.getPrincipal().toString();Object password=token.getCredentials();log.info("shiro正在处理尝试登录的用户信息:"+loginname+",密码:"+new String((char[])password));//数据库中的用户信息UserInfo user =userService.queryUserInfoByLoginName(loginname);if(user==null||CommonUtil.isNull(user.getLoginusername(),user.getPassword(),user.getSystemuserid())){return null;}log.info("shiro获取到当前用户尝试登录的真实数据:"+user.getLoginusername()+",密码:"+user.getPassword());//数据库中的正确的账户信息AuthenticationInfo accountInfo =new SimpleAuthenticationInfo(user, user.getPassword(),getName());//自己获取密码验证器(由于shiro实现的密码校验方法是密码错误会直接抛异常,不采用,所以改成直接手动校验)CredentialsMatcher matcher=getCredentialsMatcher();if(matcher==null){log.error("没有配置密码匹配器");return null;}//校验密码if(matcher.doCredentialsMatch(token,accountInfo)){return accountInfo;//校验通过,返回账号信息}return null;}}

2、自定义密码校验器


/** * 自定义shiro密码匹配(密码是在md5散列值的基础上再次进行md5加盐操作,加盐值不保存在数据库,而是放在配置文件中) * @author eguid * */public class MyCredentialsMatcher extends CodecSupport implements CredentialsMatcher {private static final Logger log = LoggerFactory.getLogger(MyCredentialsMatcher.class);protected Object getCredentials(AuthenticationToken token) {return token.getCredentials();}protected Object getCredentials(AuthenticationInfo info) {return info.getCredentials();}@Autowiredprivate CommonConfigs commonConfigs;/** * 验证密码 *  * @param tokenCredentials * @param accountCredentials * @return */protected boolean equals(Object tokenCredentials, Object accountCredentials) {if (log.isDebugEnabled()) {log.debug("Performing credentials equality check for tokenCredentials of type ["+ tokenCredentials.getClass().getName() + " and accountCredentials of type ["+ accountCredentials.getClass().getName() + "]");}if (isByteSource(tokenCredentials) && isByteSource(accountCredentials)) {if (log.isDebugEnabled()) {log.debug("Both credentials arguments can be easily converted to byte arrays.  Performing "+ "array equals comparison");}byte[] tokenBytes = toBytes(tokenCredentials);byte[] accountBytes = toBytes(accountCredentials);return MessageDigest.isEqual(tokenBytes, accountBytes);} else {return accountCredentials.equals(tokenCredentials);}}public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {Object tokenCredentials = getCredentials(token);Object accountCredentials = getCredentials(info);String account=String.valueOf((char[])tokenCredentials);if(commonConfigs.getMd5salt()==null){if (log.isDebugEnabled()) {log.debug("配置文件中的加盐值为空,无法进行密码匹配,请确认配置文件是否在指定位置或配置指定加盐值");}return false;}String saltaccount=MD5Util.getMD5(account, commonConfigs.getMd5salt());if (log.isDebugEnabled()) {log.debug("加盐后的密码:"+saltaccount);}return equals(accountCredentials, saltaccount.toCharArray());}}

三、注解使用及模板标签使用(其中注解无效)

1、注解使用

@RequiresPermissions({"user:update:view"})//检查操作权限

@RequiresPermissions(value={"user:add","user:view"},logical=Logical.OR)//两个操作权限其中一个满足条件即可通过检查

@RequiresRoles({"admin"})//检查角色

@RequiresRoles(value={"debug","admin"},logical=Logical.OR)//两个角色其中一个角色满足条件即可


@RequiresAuthentication//检查是否通过shiro认证
@RequiresGuest//不需要验证
@RequiresUser//检查用户是否是当前系统中的用户


2、标签使用

使用标签需要先导入shiro的标签库<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

(1)显示用户身份信息

<shiro: principal/>
默认调用Subject.getPrincipal()获取


<shiro:principal property="username"/>

相当于((User)Subject.getPrincipals()).getUsername()


(2)已登录shiro用户显示

 <shiro:user>  
欢迎[<shiro:principal/>]登录,<a href="logout">退出</a>  
<shiro:user>

(3)匿名用户访问

<shiro:guest>未经过shiro验证的用户(游客,匿名用户)</shiro:guest>  


(4)已经在shiro登录过的(已登录用户)

 <shiro:authenticated>  
    用户[<shiro:principal/>]已身份验证通过  
<shiro:authenticated> 

(5)没有在shiro登录过的

 <shiro:notAuthenticated>
    未身份验证(包括记住我)
<shiro:notAuthenticated>

(6)检查角色

 <shiro:hasRole name="admin">
    用户[<shiro:principal/>]拥有角色admin<br/>
<shiro:hasRole>

检查任意角色(其中一个满足条件即通过,相当于OR)
 <shiro:hasAnyRoles name="admin,user">
    用户[<shiro:principal/>]拥有角色admin或user<br/>
<shiro:hasAnyRoles>

不具有角色(反向判断)
 <shiro:lacksRole name="abc">
    用户[<shiro:principal/>]不具有角色abc<br/>
<shiro:lacksRole>

(7)操作权限判断

 <shiro:hasPermission name="user:create">  
    用户[<shiro:principal/>]拥有权限user:create<br/>  
<shiro:hasPermission>    

不具有操作权限(反向判断)
 <shiro:lacksPermission name="org:create">  
    用户[<shiro:principal/>]没有权限org:create<br/>  
<iro:lacksPermission>  



四、注解不生效解决办法

把shiro注解放到springMVC的注解扫描之后(即放在springMVC容器中加载)

<!-- 使用shiro安全检查注解 --><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" /><bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"><property name="securityManager" ref="securityManager" /></bean>
把上面的shiro直接扫描放到下面的servlet-context.xml中即可让shiro注解生效

<!-- springMVC应用 --><servlet><servlet-name>appServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/spring/servlet-context.xml</param-value></init-param><load-on-startup>2</load-on-startup></servlet><servlet-mapping><servlet-name>appServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping>






原创粉丝点击