起步
Shiro官方网站
这是一个很简单的安全框架
我们的目标是搭建一个无session的认证授权系统
项目整合
Maven配置文件
<!-- shiro权限认证 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.3</version>
</dependency>
web.xml文件修改
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
<!-- 增加了一个shiro的配置文件 -->
classpath:hcm-shiro.xml
classpath:hcm-context.xml
</param-value>
</context-param>
<!-- shiro 安全过滤器 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->
<!--filter比bean优先加载,若由spring管理则filter中注入的bean就为Null-->
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
shiro配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- Realm实现 -->
<bean id="statelessRealm" class="com.yun.hcmserver.common.shiro.TokenRealm">
<property name="cachingEnabled" value="false"/>
</bean>
<!-- Subject工厂 -->
<bean id="subjectFactory" class="com.yun.hcmserver.common.shiro.StatelessDefaultSubjectFactory"/>
<!-- 会话管理器 -->
<bean id="sessionManager" class="org.apache.shiro.session.mgt.DefaultSessionManager">
<property name="sessionValidationSchedulerEnabled" value="false"/>
</bean>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="statelessRealm"/>
<property name="subjectDAO.sessionStorageEvaluator.sessionStorageEnabled" value="false"/>
<property name="subjectFactory" ref="subjectFactory"/>
<property name="sessionManager" ref="sessionManager"/>
</bean>
<!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
<property name="arguments" ref="securityManager"/>
</bean>
<bean id="statelessAuthcFilter" class="com.yun.hcmserver.common.shiro.StatelessAuthcFilter"/>
<!-- Shiro的Web过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="filters">
<util:map>
<entry key="statelessAuthc" value-ref="statelessAuthcFilter"/>
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
/login=anon
/reg=anon
/forget=anon
/logout=anon
/assets/**=anon
/resource/**=anon
/web/org/**=statelessAuthc,roles[role1]
/web/user/**=statelessAuthc,roles[role2]
/**=statelessAuthc
</value>
</property>
</bean>
<!-- Shiro生命周期处理器-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>
代码编写
Realm的实现 TokenRealm
public class TokenRealm extends AuthorizingRealm {
@Override
public boolean supports(AuthenticationToken token) {
//仅支持StatelessToken类型的Token
return token instanceof StatelessToken;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
if (principals == null) {
throw new AuthorizationException("用户身份不能为空!");
}
Long userId = (Long)getAvailablePrincipal(principals);
// 根据用户名查找角色,请根据需求实现
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 设置权限角色
authorizationInfo.addRoles(gerUserRole(userId));
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
StatelessToken statelessToken = (StatelessToken) token;
String serverInfo = statelessToken.getToken();
Long userId = checkToken(statelessToken.getToken(),statelessToken.getApp());
// 密码信息与Token中的认证信息一致则通过身份认证
return new SimpleAuthenticationInfo(
userId, // 用户名
serverInfo, // 密码信息
getName());
}
private Collection<String> gerUserRole(Long userId){
// 测试用角色
Collection<String> roleInfo = new HashSet<String>();
roleInfo.add("role1");
roleInfo.add("role2");
return roleInfo;
}
public Long checkToken(String token,boolean isClient) {
// 验证登录的Token是否正确
if("jijdojiejae".equals(token)){
return 233L;
}else{
return null;
}
}
}
自定义的Token
public class StatelessToken implements AuthenticationToken {
private static final long serialVersionUID = 1L;
private String token;
private boolean isApp;
public StatelessToken(String token,boolean isApp) {
this.token = token;
this.isApp = isApp;
}
public boolean getApp() {
return isApp;
}
public void setApp(boolean isApp) {
this.isApp = isApp;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}
Subject工厂类
public class StatelessDefaultSubjectFactory extends DefaultWebSubjectFactory {
@Override
public Subject createSubject(SubjectContext context) {
//不创建session
context.setSessionCreationEnabled(false);
return super.createSubject(context);
}
}
无状态权限过滤器
public class StatelessAuthcFilter extends AccessControlFilter {
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
return false;
}
@Override
protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String token = request.getParameter(ComConst.TOKEN_PARAM_NAME);
boolean isApp = false;
StatelessToken loginToken = new StatelessToken(token, isApp);
try {
// 委托给Realm进行登录
getSubject(request, response).login(loginToken);
} catch (Exception e) {
// 登录失败的情况下
if(isApp){
ReturnBean bean = new ReturnBean();
bean.setMessage("not login");
bean.setStatus(ReturnTypeEnum.Restart);
bean.setData("");
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
response.getWriter().print(gson.toJson(bean));
}else{
response.sendRedirect(request.getContextPath() + "/login");
}
return false;
}
return true;
}
}