Skip to content

Commit 5c7fd49

Browse files
author
Songyu
committed
增加文章springmvci集成shiro(多身份)
1 parent 8d8fc65 commit 5c7fd49

File tree

2 files changed

+233
-0
lines changed

2 files changed

+233
-0
lines changed
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
---
2+
layout: post
3+
title: "springMVCi集成shiro(多身份)"
4+
date: 2020-10-25 21:08:58 +0800
5+
tags: java
6+
description:
7+
---
8+
9+
最近的生活,真是一言难尽。。。不多说了,直接进入正题吧。
10+
11+
以前做项目的时候,对于用户登录这边,基本用的就是拦截器,多身份得话,就在拦截器中进行判断。在浏览帖子的时候,看到了关于shiro的介绍,又正巧要做一个新的项目。于是在新的项目中,用户的权限管理就改用shiro去控制。
12+
13+
关于shiro,就不多介绍了,一个轻量的用户权限管理包;项目的要求也很简单。后台管理员和前台用户两个身份分别进行登录,访问各自的url。
14+
15+
首先,通过maven引入shiro的jar包
16+
{% highlight xml %}
17+
<dependency>
18+
<groupId>org.apache.shiro</groupId>
19+
<artifactId>shiro-core</artifactId>
20+
<version>1.4.0</version>
21+
</dependency>
22+
<dependency>
23+
<groupId>org.apache.shiro</groupId>
24+
<artifactId>shiro-web</artifactId>
25+
<version>1.4.0</version>
26+
</dependency>
27+
<dependency>
28+
<groupId>org.apache.shiro</groupId>
29+
<artifactId>shiro-spring</artifactId>
30+
<version>1.4.0</version>
31+
</dependency>
32+
<dependency>
33+
<groupId>org.apache.shiro</groupId>
34+
<artifactId>shiro-ehcache</artifactId>
35+
<version>1.4.0</version>
36+
</dependency>
37+
<dependency>
38+
<groupId>net.mingsoft</groupId>
39+
<artifactId>shiro-freemarker-tags</artifactId>
40+
<version>1.0.0</version>
41+
</dependency>
42+
{% endhighlight %}
43+
44+
然后,创建spring-shiro.xml文件,对shiro进行配置,需要注意的几个配置点:
45+
46+
> 多身份用户,对应多个realm对象
47+
>
48+
> 不同身份下的身份验证规则(FormAuthenticationFilter类或者重写的继承类)
49+
>
50+
> shiro的主filter配置(ShiroFilterFactoryBean),包括filters(过滤规则)、filterChainDefinitions(设置url对应的过滤规则)
51+
52+
配置文件如下:
53+
{% highlight xml %}
54+
<!-- 配置filter -->
55+
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
56+
<property name="securityManager" ref="securityManager"></property>
57+
<property name="filters">
58+
<map>
59+
<entry key="adminFilter" value-ref="AdminFilter"></entry>
60+
<entry key="userFilter" value-ref="UserFilter"></entry>
61+
<entry key="adminPermissionFilter" value-ref="AdminPermissionFilter"></entry>
62+
</map>
63+
</property>
64+
<property name="filterChainDefinitions">
65+
<value>
66+
/static/**=anon
67+
/admin/base/login/*=anon
68+
/index=anon
69+
/admin/**=adminFilter,adminPermissionFilter
70+
/ucenter/auth/**=anon
71+
/ucenter/**=userFilter
72+
</value>
73+
</property>
74+
</bean>
75+
76+
<!-- 配置securityManager -->
77+
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
78+
<!-- 引入ModularRealmAuthenticator类 -->
79+
<property name="authenticator" ref="CustomerModularRealmAuthenticator"></property>
80+
<!-- 配置多个realm对象 -->
81+
<property name="realms">
82+
<list>
83+
<ref bean="AdminRealm"></ref>
84+
<ref bean="TeacherRealm"></ref>
85+
<ref bean="UserRealm"></ref>
86+
</list>
87+
</property>
88+
</bean>
89+
<!-- 自定义realm -->
90+
<!-- 后台对象realm -->
91+
<bean id="AdminRealm" class="com.bc.core.shiro.realm.AdminRealm"></bean>
92+
<!-- 教师端realm -->
93+
<bean id="TeacherRealm" class="com.bc.core.shiro.realm.TeacherRealm"></bean>
94+
<bean id="UserRealm" class="com.bc.core.shiro.realm.UserRealm"></bean>
95+
96+
<!-- 配置filter对应的登陆页面 -->
97+
<bean id="AdminFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
98+
<property name="loginUrl" value="/admin/base/login/index"></property>
99+
</bean>
100+
<bean id="UserFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
101+
<property name="loginUrl" value="/ucenter/auth/login"></property>
102+
</bean>
103+
104+
<!-- 自定义后台权限验证filter -->
105+
<bean id="AdminPermissionFilter" class="com.bc.core.shiro.authz.AdminPermissionFilter">
106+
<property name="loginUrl" value="/admin/base/login/index"></property>
107+
<property name="unauthorizedUrl" value="/admin/main/error/authz"></property>
108+
</bean>
109+
110+
<!-- 自定义ModularRealmAuthenticator类,选则当前要使用的realm -->
111+
<bean id="CustomerModularRealmAuthenticator" class="com.bc.core.shiro.authc.CustomerRealmAuthenticator">
112+
<property name="authenticationStrategy">
113+
<!-- 配置认证策略,只要有一个Realm认证成功即可,并且返回所有认证成功信息 -->
114+
<bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>
115+
</property>
116+
</bean>
117+
<!-- 配置 Bean 后置处理器: 会自动的调用和 Spring 整合后各个组件的生命周期方法. -->
118+
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
119+
{% endhighlight %}
120+
121+
在用户登录的时候,需要把用户的登录名、密码传入到UsernamePasswordToken类中,由于我们是两种身份不同的用户,所以需要对UsernamePasswordToken类进行拓展,增加loginType参数
122+
{% highlight java %}
123+
//UsernamePasswordToken拓展类
124+
public class CustomerToken extends UsernamePasswordToken {
125+
126+
private TokenTypeEnum loginType;
127+
128+
public CustomerToken(String username,String password,TokenTypeEnum loginType){
129+
super(username,password);
130+
this.loginType = loginType;
131+
}
132+
133+
public CustomerToken(String username,String password,TokenTypeEnum loginType,boolean rememberme){
134+
super(username,password,rememberme);
135+
this.loginType = loginType;
136+
}
137+
138+
public TokenTypeEnum getLoginType() {
139+
return loginType;
140+
}
141+
142+
public void setLoginType(TokenTypeEnum loginType) {
143+
this.loginType = loginType;
144+
}
145+
146+
}
147+
148+
//loginType枚举类
149+
public enum TokenTypeEnum {
150+
151+
Admin("Admin"),User("User");
152+
153+
private String type;
154+
155+
TokenTypeEnum(String type){
156+
this.type = type;
157+
}
158+
159+
public String getType() {
160+
return type;
161+
}
162+
163+
public void setType(String type) {
164+
this.type = type;
165+
}
166+
167+
}
168+
{% endhighlight %}
169+
170+
这样在登录时候原本调用的UserPasswordToken可以改为新的自定义类,并增加LoginType参数
171+
{% highlight java %}
172+
Subject subject = SecurityUtils.getSubject();
173+
UsernamePasswordToken usernamePasswordToken = new CustomerToken(username,password,TokenTypeEnum.Admin);
174+
subject.login(usernamePasswordToken);
175+
{% endhighlight %}
176+
177+
不同身份对应的用户信息验证,在自定义的realm类中,进行实现
178+
{% highlight java %}
179+
//继承AuthorizingRealm类,实现自己的逻辑
180+
public class UserRealm extends AuthorizingRealm {
181+
182+
@Autowired
183+
private IUserDao userDao;
184+
185+
@Autowired
186+
private IUserBaseDao userBaseDao;
187+
188+
@Autowired
189+
private SessionDAO sessionDAO;
190+
191+
//权限注入函数
192+
@Override
193+
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
194+
return null;
195+
}
196+
197+
//用户认证函数
198+
@Override
199+
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
200+
//获取登录用户名
201+
String username = (String)authenticationToken.getPrincipal();
202+
UserEntity userEntity = userDao.getOne(MapUtil.getMap("mobile",username,"isdel",0));
203+
if(userEntity == null){
204+
throw new UnknownAccountException("用户名或密码错误!");
205+
}
206+
//验证密码是否正确
207+
char[] pass = (char[])authenticationToken.getCredentials();
208+
String password = String.valueOf(pass);
209+
if(!userEntity.getPassword().equals(MD5.encryption(password))){
210+
throw new IncorrectCredentialsException("用户名或密码错误!");
211+
}
212+
//验证成功,赋值对象属性
213+
User user = new User();
214+
BeanUtils.copyProperties(userEntity,user);
215+
UserBaseEntity userBaseEntity = userBaseDao.getOne(MapUtil.getMap("userid",userEntity.getId()));
216+
if(userBaseEntity!= null){
217+
user.setName(userBaseEntity.getName());
218+
user.setAvatar(userBaseEntity.getAvatar());
219+
}
220+
221+
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(admin,pass,getName());
222+
223+
return simpleAuthenticationInfo;
224+
}
225+
}
226+
{% endhighlight %}
227+
228+
至此,多身份的登录流程就写完了,但是,突然发现在同一个浏览器登录两个身份的时候,前一个SimpleAuthenticationInfo中的principal对象会报错,后一个把前一个替换掉了,再去访问前一个的话,就会出现对象类型错误。
229+
230+
研究了一阵子。。虽然说是解决了,但是不知道其他人是怎么弄的,网上找了好多,也没找到类型的问题(是我找的不对吗)。
231+
![](/images/2020-10-26-1.jpg)
232+
233+
下一篇文章,去说一下我的解决办法。

images/2020-10-26-1.jpg

12.2 KB
Loading

0 commit comments

Comments
 (0)