XML配置
1. 配置web.xml
配置
springShiro.xml
文件读取1
2
3
4<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml classpath:springShiro.xml</param-value>
</context-param>可以和
applicationContext.xml
一起写。配置过滤器
1
2
3
4
5
6
7
8
9
10
11
12
13<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>注意这里filter的名字必须为:
shiroFilter
。因为Shiro内部是直接读取名字的。配置springShiro.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- proxy-target-class="true"强制使用CGLib代理,为false则spring会自动选择,否则事务不生效 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<!-- 配置relam -->
<bean id="tidyRealm" class="priv.mw.shiro.TidyRealm"></bean>
<!-- 配置权限管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realms" ref="tidyRealm" />
<property name="cacheManager" ref="cacheManager" />
</bean>
<bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />
<bean id="tidyFilter" class="priv.mw.filter.JWTFilter"/>
<!-- 配置shiro的过滤器工厂类,id- shiroFilter要和我们在web.xml中配置的过滤器一致 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 调用我们配置的权限管理器 -->
<property name="securityManager" ref="securityManager" />
<property name="filters">
<map>
<entry key="tidyFilter" value-ref="tidyFilter"/>
</map>
</property>
<property name="filterChainDefinitions">
<value>
/login/**=anon
/register/**=anon
/**=tidyFilter
</value>
</property>
</bean>
<!-- 配置shiro bean生命周期管理类 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
</beans>其中最主要的是filter的配置,因为这里结合的是JWT,并不是基于session,所以并不需要shiro来帮助我们保存用户信息。
然后就是
ShiroFilterFactoryBean
的配置。其中会配置
securityManager
和filters
,其中filterChainDefinitions
是用来进行url权限地址认证:其中有几个点:
- url中的
*
表示任意一级url匹配。比如:/url/*
可以匹配/url/a
或者/url/aaa
,但不能匹配/url/a/aa
因为产生2级目录了。 - url中的
**
表示任意多级的url匹配。比如/url/**
既可以匹配/url/a
又可以匹配/url/a/aa
=
后是需要的权限,可以是shiro定义的Filter,也可以是我们自己定义的Filter。其内置的有filter,并且有简写- anon—————org.apache.shiro.web.filter.authc.AnonymousFilter
- authc————–org.apache.shiro.web.filter.authc.FormAuthenticationFilter
- authcBasic———org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
- logout————-org.apache.shiro.web.filter.authc.LogoutFilter
- noSessionCreation–org.apache.shiro.web.filter.session.NoSessionCreationFilter
- perms————–org.apache.shiro.web.filter.authz.PermissionAuthorizationFilter
- port—————org.apache.shiro.web.filter.authz.PortFilter
- rest—————org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
- roles————–org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
- ssl—————-org.apache.shiro.web.filter.authz.SslFilter
- user—————org.apache.shiro.web.filter.authz.UserFilter
这里还没有做授权,所以Realm并没有贴出来,本来应该是从token中拿出id,然后去查询数据库,看权限是否合法。
可以在
FormAuthenticationFilter
中通过getSubject(servletRequest, servletResponse)
获取subject来进行登录。tidyFilter
下面是
tidyFilter
的代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54public class JWTFilter extends FormAuthenticationFilter {
ObjectMapper mapper = new ObjectMapper();
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest req = (HttpServletRequest) request;
String rawToken = req.getHeader("Authorization");
response.setContentType("text/json;charset=utf-8");
if(rawToken == null || "".equals(rawToken)){
try {
response.getWriter().println(mapper.writeValueAsString(Result.data("").msg("未认证,请先认证!").code(401)));
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}else {
String token = rawToken.substring(7);
boolean tokenValid = JWTUtils.checkToken(token);
if(!tokenValid){
try {
response.getWriter().println(mapper.writeValueAsString(Result.data("").msg("认证已过期,请重新登录!").code(401)));
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}else {
return true;
}
}
}
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
HttpServletRequest req = (HttpServletRequest) request;
String token = req.getHeader("Authorization");
response.setContentType("text/json;charset=utf-8");
if(token == null || "".equals(token)){
return false;
}else {
boolean tokenValid = JWTUtils.checkToken(token);
if(!tokenValid){
return false;
}else{
return true;
}
}
}
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
return super.executeLogin(request, response);
}
}这个类就是用来验证header中携带的token信息,由于其是无状态的。所以直接通过工具类验证就行了。
这个类继承了
FormAuthenticationFilter
,其两个方法:isAccessAllowed
:判断这个请求是否允许。onAccessDenied
:如果不允许,则引导用户进行认证。(此处是直接返回false,并返回未认证的JSON)
- url中的
下面是一个简单的JWTUtils,有待加强:
1 | public class JWTUtils { |