用 shiro 實(shí)現(xiàn)最基本的登錄認(rèn)證是一件非常簡(jiǎn)單的事情,我覺得官網(wǎng)給的例子不太好用,反正我是沒搞出來,現(xiàn)在寫一份自己的教程。
項(xiàng)目地址:https://github.com/thecattle/spring-mvc-shiro
目的
- 集成 shiro 到 spring 上
- 實(shí)現(xiàn)最基本的登錄認(rèn)證
項(xiàng)目環(huán)境
- spring+spring-mvc
- maven3
- IntelliJ IDEA
- jdk1.8
1. 添加 shiro 配置
1.1 修改 pom 文件
添加 shiro maven :
<!--shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
1.2 修改 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>
1.3 為了項(xiàng)目結(jié)構(gòu)清晰,單獨(dú)新建 shiro 配置文件
在 resource 目錄新建 shiro.xml

image.png
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm">
<!--自定義 MyRealm,登錄的認(rèn)證入口 ,需要繼承AuthorizingRealm,項(xiàng)目中會(huì)體現(xiàn)-->
<bean class="com.sunp.shiro.MyRealm"></bean>
</property>
</bean>
<!--shiro 請(qǐng)求攔截器,這里的 bean id 一定要對(duì)應(yīng) web.xml 中的filter-name,否則找不到這個(gè)攔截器-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"></property>
</bean>
<!-- 保證實(shí)現(xiàn)了Shiro內(nèi)部lifecycle函數(shù)的bean執(zhí)行 ,不明覺厲,沒有深究-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>
1.4 修改 spring 配置文件 applicationContext.xml
將 shiro.xml導(dǎo)入到 spring 容器中
<?xml version="1.0" encoding="UTF-8"?>
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--啟用spring的一些annotation -->
<context:annotation-config/>
<!--在 shiro 中用到了 UserService,shiro 是運(yùn)行在 spring 容器中的, shiro 和 spring-mvc 級(jí)別是平行的,
所以 spring-mvc 的掃描不起作用,這里再掃描一次,所有的 bean 加載到 spring 容器中-->
<context:component-scan base-package="com.sunp.**"></context:component-scan>
<!--導(dǎo)入 shiro 配置-->
<import resource="classpath:shiro.xml"></import>
</beans>
配置到這里就差不多了。
2. 添加 shiro 項(xiàng)目代碼
2.1 新建自定義的 realm
我這里創(chuàng)建在 com.sunp.shiro包下,對(duì)應(yīng) shiro.xml 中的配置。仔細(xì)看注釋
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 認(rèn)證用戶的操作
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
//從假數(shù)據(jù)源中拿當(dāng)前用戶數(shù)據(jù)
User userDao = userService.getUserInfo(token.getUsername());
if (userDao==null){
//扔出個(gè)異常,currentUser.login(token);可以 catch 到
throw new UnknownAccountException("未知用戶");
}
//如果數(shù)據(jù)庫中存在這個(gè)用戶名
if(userDao.getUserName().equals(token.getUsername())){
//創(chuàng)建認(rèn)證對(duì)象,傳入數(shù)據(jù)庫存在的對(duì)象賬號(hào)和密碼,內(nèi)部會(huì)根據(jù) currentUser.login(token) 的 token 進(jìn)行比較
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(userDao.getUserName(), userDao.getUserPassword(), this.getName());
return authcInfo;
}
return null;
}
}
2.2 在 LoginController 中添加登錄方法
//方便調(diào)試 直接用 get
@RequestMapping(value = "/login",method = RequestMethod.GET)
@ResponseBody
public Map<String,Object> login(String username,String password){
Map<String,Object> map=new HashMap<>();
logger.info("開始登錄");
//構(gòu)建登錄 token
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//設(shè)置記住我
token.setRememberMe(true);
//獲取當(dāng)前登錄用戶
Subject currentUser = SecurityUtils.getSubject();
try {
//登錄
currentUser.login(token);
//判斷用戶狀態(tài)是否已經(jīng)被認(rèn)證
if (currentUser.isAuthenticated()){
map.put("msg","登錄成功");
}else {
map.put("msg","系統(tǒng)異常,請(qǐng)重試");
}
} catch (UnknownAccountException uae) {
map.put("msg","未知用戶");
} catch (IncorrectCredentialsException ice) {
map.put("msg","認(rèn)證失敗");
} catch (LockedAccountException lae) {
map.put("msg","賬戶已鎖定");
} catch (ExcessiveAttemptsException eae) {
map.put("msg","登錄失敗次數(shù)過多");
} catch (AuthenticationException ae) {
map.put("msg",ae.getMessage());
}
return map;
}
3. 項(xiàng)目結(jié)構(gòu)
最后的項(xiàng)目結(jié)構(gòu)如下:藍(lán)色為修改過文件,綠色為新增文件

image.png
4. 測(cè)試
4.1 假的數(shù)據(jù)源為:

image.png
4.2 測(cè)試正確

image.png
4.3 測(cè)試不存在的用戶

image.png
4.4 測(cè)試錯(cuò)誤的密碼

image.png
自學(xué)筆記,如有錯(cuò)誤,期待評(píng)論指正