安全框架Apache Shiro学习心得

时间:2022-12-11 20:10:35

关于Shiro的介绍网上有太多,就不赘述了,写这篇文章的目的就是记录一下使用配置的要点。

1. Web.xml配置,Shiro的filter必须放在其他filter之前

<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. Spring Context配置,都是官网摘来的,就不详述了。有以下问题需要注意:

     1) Shiro提供的realm没有需要的,所以自己写了个

     2) successUrl和unauthorizedUrl调试时曾经没有起作用,后来莫名其妙好了,原因不明,可能是开始代码或配置有问题,比如:为了测试权限注解,在login Action里调用了一个加上了@RequiresPermissions("account:create")的private method,不深究了。

<!-- shiro security -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login"/>
<property name="successUrl" value="/welcome"/>
<property name="unauthorizedUrl" value="/refuse"/>
<property name="filterChainDefinitions">
<value>
/refuse = anon
<!-- /welcome = perms[accout:edit] -->
/** = authc
</value>
</property>
</bean>

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="customRealm"/>
</bean>
<bean id="customRealm" class="com.capgemini.framework.common.access.CustomShiraRealm" />

<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

3. 为了支持Shiro的注释,按官方文档的介绍,在applicationContext.xml加两个bean定义:DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor。

可是测试下来却不起作用,搜了半天,终于找到原因,原来用了spring mvc的话就需要把这两个bean定义写在相应的springmvc-servlet.xml文件中,并加上SimpleMappingExceptionResolver

<!-- Support Shiro Annotation -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.apache.shiro.authz.UnauthorizedException">shiro-test/refuse</prop>
</props>
</property>
</bean>
<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>

4. 自定义的realm必须继承AuthorizingRealm,并实现两个Abstract方法doGetAuthorizationInfo和doGetAuthenticationInfo

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.fromRealm(getName()).iterator().next();
if (username != null) {
try {
User user = userMgntService.getUserByUserCode(username);
if (user != null && user.getRole() != null) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRole(user.getRole().getRoleName());
info.addStringPermission("account:view");
return info;
}
} catch (AppException e) {
logger.error(e, e);
}
}
return null;

}
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken ) throws AuthenticationException {UsernamePasswordToken token = (UsernamePasswordToken) authcToken;String userName = token.getUsername();if (userName != null && !"".equals(userName.trim())) {try {User user = userMgntService.getUserByUserCode(token.getUsername());if (user != null && user.getPassword().equals(String.valueOf(token.getPassword())))return new SimpleAuthenticationInfo(user.getUserCode(),                                                  user.getPassword(), getName());} catch (AppException e) {logger.error(e, e);}}return null;}

5. 如果jsp的login form按照官方文档的写法,表单元素的名字都和文档一样的话,那么login Action基本不需要做太多操作,只需要完成验证失败的跳转。验证成功的话不会回到/login,而是从realm一直往下走跳到successUrl,默认的FormAuthenticationFilter会找这三个requestparameters:username,password andrememberMe,如果非要用不一样的名字,那么就设置FormAuthenticationFilter的这几个参数

<form action="${pageContext.request.contextPath}/login" method="post">

Username: <input type="text" name="username"/> <br/>
Password: <input type="password" name="password"/>
...
<input type="checkbox" name="rememberMe" value="true"/>Remember Me?
...
</form>

[main]...authc.loginUrl = /whatever.jspauthc.usernameParam = somethingOtherThanUsernameauthc.passwordParam = somethingOtherThanPasswordauthc.rememberMeParam = somethingOtherThanRememberMe...

@RequestMapping(value = "/login")
public String login(String username, String password) {
return "shiro-test/login";
}