将 Apache Shiro 改造成 JWT 认证方式
2017-09-30 00:38
411 查看
要想成功改造,只需做到三点
1.用 Shiro 提供的 DefaultWebSessionManager 替代默认的 ServletContainerSessionManager- ServletContainerSessionManager 是 DefaultWebSecurityManager 使用的默认实现,用于 Web 环境,其直接使用 Servlet 容器的会话
- 因为我们无法控制服务器(例如 Tomcat)的会话管理,所以要自己维护会话池,即使用 DefaultWebSessionManager
2.自定义 SessionIdCookie 模板,其默认从 Cookie 读取 SessionId,但我们需要从请求头部读取 Token 字段
3.自定义 SessionIdGenerator,默认的 JavaUuidSessionIdGenerator 产生一个随机的 UUID 值来做 SessionId,但我们需要用 jwt 串作 SessionId
shiro.ini
[main] #自定义会话 Cookie 模板,重写方法,使得从请求头部或参数读取 SessionId,而非 Cookie sessionIdCookie=com.pomer.test.servlet.MySimpleCookie #使用 Shiro 提供的 DefaultWebSessionManager,其维护自己的会话池,从而废弃服务器的会话池 sessionManager=org.apache.shiro.web.session.mgt.DefaultWebSessionManager sessionIdCookie.name=Token #sessionIdCookie.domain=sishuok.com #sessionIdCookie.path= #sessionIdCookie.maxAge=1800 sessionIdCookie.httpOnly=true sessionManager.sessionIdCookie=$sessionIdCookie sessionManager.sessionIdCookieEnabled=true #自定义会话 ID 生成器(SessionId 返回 JWT 串,而非随机 UUID) sessionIdGenerator=com.pomer.test.servlet.MySessionIdGenerator #如果考虑分布式服务器,可以自定义数据库存储会话 Dao,这里使用了内存存取会话 sessionDAO=org.apache.shiro.session.mgt.eis.MemorySessionDAO sessionDAO.sessionIdGenerator=$sessionIdGenerator sessionManager.sessionDAO=$sessionDAO securityManager.sessionManager=$sessionManager #以下为 JWT 无关配置,请忽略 #声明 JdbcRealm jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm jdbcRealm.permissionsLookupEnabled=true jdbcRealm.authenticationQuery=SELECT password FROM user WHERE username = ? jdbcRealm.userRolesQuery=SELECT r.name FROM role r JOIN user u ON r.id = u.role_id WHERE u.username = ? jdbcRealm.permissionsQuery=SELECT a.name FROM authority a JOIN link_role_authority l ON a.id = l.authority_id JOIN role r ON r.id = l.role_id WHERE r.name = ? #设置数据库 dataSource=com.alibaba.druid.pool.DruidDataSource dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql://localhost:3306/web?useSSL=false dataSource.username=web dataSource.password=123456 jdbcRealm.dataSource=$dataSource #指定 securityManager 的 realms 实现 securityManager.realms=$jdbcRealm #设置 url authc.loginUrl=/login roles.unauthorizedUrl=/unauthorized perms.unauthorizedUrl=/unauthorized [urls] #无需用户认证 /login=anon /logout=anon /unauthorized=anon /static/**=anon #需要用户认证 /authenticated=authc #用户认证 + 角色验证 /role=authc,roles[admin] #用户认证 + 权限验证 /permission=authc,perms["user_add"]
MySimpleCookie
public class MySimpleCookie extends SimpleCookie { @Override public String readValue(HttpServletRequest request, HttpServletResponse ignored) { //读取 SessionId,即 jwt 串 String value = request.getHeader(getName()); if (value == null) value = request.getParameter(getName()); return value; } }
MySessionIdGenerator
public class MySessionIdGenerator extends JavaUuidSessionIdGenerator { static int count = 0; @Override public Serializable generateId(Session session) { //如果进行了基于 JWT 的用户认证,可以获取加密生成的 JWT 串并返回,<JWT, Session> 存入 Shiro 会话池 // SessionId 即为 JWT 串,可通过 JWT 从会话池中获取相应的会话信息 if (++count % 2 == 0) return String.valueOf(count); //如果不存在用户认证,随便返回一个值,但不能为 null return super.generateId(session); } }
index.jsp
<%@ page import="org.apache.shiro.SecurityUtils" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>首页</title> </head> <body> <% System.out.println("会话id:" + SecurityUtils.getSubject().getSession().getId()); System.out.println("会话创建时间:" + SecurityUtils.getSubject().getSession().getStartTimestamp()); %> </body> </html>
启动服务器,当不提供任何参数时
//可以看到不断生成新的会话 会话id:ff70105d-b192-41aa-8b66-b1c5ff0e30fd 会话创建时间:Sat Sep 30 00:16:45 CST 2017 会话id:2 会话创建时间:Sat Sep 30 00:16:46 CST 2017 会话id:7228b82d-2520-4830-bb4f-d4cf450fe982 会话创建时间:Sat Sep 30 00:16:56 CST 2017 会话id:4 会话创建时间:Sat Sep 30 00:16:56 CST 2017 会话id:45f96994-3647-4aa1-8d67-a82c436c349f 会话创建时间:Sat Sep 30 00:16:56 CST 2017 会话id:6 会话创建时间:Sat Sep 30 00:16:56 CST 2017 会话id:a3eea41d-311d-407b-9e5d-7491eaf229b4 会话创建时间:Sat Sep 30 00:16:57 CST 2017 会话id:8 会话创建时间:Sat Sep 30 00:16:57 CST 2017 会话id:3f45c24f-a1ab-462c-984d-c32060213bf8 会话创建时间:Sat Sep 30 00:16:57 CST 2017 会话id:10 会话创建时间:Sat Sep 30 00:16:57 CST 2017
提供参数,将 URL 改为 http://localhost:8080/shiro/?token=2
//可以看到会话得到维持 会话id:2 会话创建时间:Sat Sep 30 00:16:46 CST 2017 会话id:2 会话创建时间:Sat Sep 30 00:16:46 CST 2017 会话id:2 会话创建时间:Sat Sep 30 00:16:46 CST 2017 会话id:2 会话创建时间:Sat Sep 30 00:16:46 CST 2017 会话id:2 会话创建时间:Sat Sep 30 00:16:46 CST 2017 会话id:2 会话创建时间:Sat Sep 30 00:16:46 CST 2017 会话id:2 会话创建时间:Sat Sep 30 00:16:46 CST 2017 会话id:2 会话创建时间:Sat Sep 30 00:16:46 CST 2017
相关文章推荐
- apache shiro与spring整合、动态filterChainDefinitions、以及认证、授权
- Apache Shiro 认证、授权、加密和会话管理
- Apache Shiro 使用手册(二)Shiro 认证
- 安全认证框架-apache shiro研究心得
- Apache Shiro 使用手册(二)Shiro 认证
- 【Shiro】Apache Shiro架构之身份认证(Authentication)
- Apache Shiro 标签方式授权
- Apache Shiro的运行流程和权限控制方式分析
- 使用Apache Shiro进行身份认证-LDAP两次绑定认证
- Apache Shiro 使用手册(二)Shiro 认证
- 2 Apache Shiro 身份认证(登录)
- 采用ApacheShiro来实现应用的权限认证
- shiro认证流程初(ini方式)
- 【Shiro】Apache Shiro架构之权限认证(Authorization)
- 【Shiro】Apache Shiro架构之身份认证(Authentication)
- 【Shiro】Apache Shiro架构之身份认证(Authentication)
- apache shiro与spring整合、动态filterChainDefinitions、以及认证、授权
- Apache Shiro 使用手册(二)Shiro 认证
- apache shiro与spring整合、动态filterChainDefinitions、以及认证、授权
- Apache Shiro 使用手册(二)Shiro 认证