概述
这里使用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 {@Autowiredprivate 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的登录。
源码地址:GitHub的Demo