概述
这里使用Shiro来实现用户的登录和登出功能。
前提:已经会Spring集成Shiro。即使没有下面也会提供源码,下面只说明Shiro部分的核心代码,如Mapper、Service类中的代码基本上就是从数据库中读取数据,而且源码有提供,不在说明。
实现
第一步:一个用于登录的页面和一个用于退出登录的页面。
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form action="/user/login" method="post">
用户名:<input type="text" name="username"/><br/>
密码:<input type="password" name="password"/><br/>
记住我:<input type="checkbox" name="rememberMe">
<input type="submit" value="登录">
<p>注:登录成功的账户是root和123456</p>
</form>
</body>
</html>
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>恭喜${sessionScope.get("user").username}登录成功!</h1>
<a href="/user/logout">退出</a>
</body>
</html>
第二步:使用Shiro实现登录
第三步:实现退出逻辑
第四步:自定义类继承AuthorizingReal,实现里面的两个方法,但登录只需要实现认证方法doGetAuthenticationInfo()方法即可。
@Component
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
// 完成授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
// 完成认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// authenticationToken是主体传过来的认证信息,如果使用的是UsernamePasswordToken,那么可以转换成该类型
UsernamePasswordToken token=(UsernamePasswordToken)authenticationToken;
// 1.获取用户输入的用户名
String username=token.getUsername();// token.getPrincipal();也是获取相同的用户名
// 2.通过用户名从数据库中查询用户信息
User user = userService.selectUserByUsername(username);
// 3.判断查询到的用户信息是否有效
if(user==null){
throw new UnknownAccountException();
}
if(0==user.getState()){// 用户状态为0,表示该用户被禁用了
throw new DisabledAccountException();
}
// 4.返回用户认证信息
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(
username,// 可以是用户名,也可以是用户信息
user.getPassword(),// 用户密码
ByteSource.Util.bytes(username),// 为密码加的盐
getName());// 固定写法,是一个名字
return info;
}
}
注意:这里的用户信息是从数据库查到的,用了Service、Mapper接口等,这属于SSM的知识,这里不做说明。
第五步:在spring的配置文件applicationContext.xml中设置自定义的Realm。
<?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" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置Shiro的认证和授权的过滤器-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="login.html"/>
<property name="unauthorizedUrl" value="403.html"/>
<property name="filterChainDefinitions">
<value>
<!--对静态资源不拦截-->
<!--anon指匿名访问的过滤器,所有匿名用户都可以访问静态资源,如css等-->
/css/*=anon
<!--登录页面可以访问-->
/login.html = anon
<!--登录请求也可以通过-->
/user/login = anon
<!--表示/testRole请求必须是admin角色才能访问,roles["角色名"]是标准格式-->
/testRole = roles["admin"]
<!--表示/testRole2请求必须同时具备admin和user角色才能访问-->
/testRole2 = roles ["admin","user"]
<!--表示/testPerms请求必须具有user:delete权限才能访问,perms["权限名"]是标准格式-->
/testPerms = perms["user:delete"]
<!--表示/testPerms2请求必须同时具有user:delete权限和user:update权限才能访问-->
/testPerms2 = perms["user:delete","user:update"]
<!--authc指必须经过认证(登录过之后)才能放弃的请求,/*指的是所有有一个斜杠的请求都要经过认证-->
<!--/**表示所有资源和请求都需要认证,/** = authc是标准格式-->
<!--/** = authc-->
<!--/**=user指的是系统中所有资源和请求需要验证通过或者RememberMe登录的都可以,/**=user是标准格式-->
/**=user
</value>
</property>
</bean>
<!--创建安全管理器SecurityManager对象-->
<bean class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" id="securityManager">
<!--声明域,在域中读取认证和授权的数据-->
<property name="realm" ref="myRealm"/>
<!--声明rememberMe管理器-->
<property name="rememberMeManager" ref="rememberMeManager"/>
</bean>
<!--配置自定义的Realm-->
<bean class="com.demo.shiro.realm.MyRealm" id="myRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean>
<!--加密管理器对象-->
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher" id="credentialsMatcher">
<!--设置加密的算法:MD5-->
<property name="hashAlgorithmName" value="md5"/>
<!--设置加密的次数-->
<property name="hashIterations" value="1"/>
</bean>
<!--配置记住我-->
<bean class="org.apache.shiro.web.mgt.CookieRememberMeManager" id="rememberMeManager">
<property name="cookie" ref="rememberMeCookie"/>
</bean>
<bean class="org.apache.shiro.web.servlet.SimpleCookie" id="rememberMeCookie">
<!--声明Cookie对象-->
<constructor-arg value="rememberMe"/>
<!--设置cookie的失效时间,单位是秒-->
<property name="maxAge" value="3600"/>
</bean>
</beans>
注意,数据库里面的密码是使用了Md5Hash加密了的,使用的盐的用户名。可以通过下面的代码来获取加密后的密文。
下面是关于配置的说明:
简化掉Shiro过滤器的配置:
第六步:在web.xml中配置Shiro的过滤器
其实上面这些步骤也是Spring集成Shiro的配置,都属于Shiro的配置。
源码
最好的办法还是看源码直观感受Shiro的登录。