将 Apache Shiro 改造成 JWT 认证方式

来源:互联网 发布:知乎俄罗斯航空发动机 编辑:程序博客网 时间:2024/05/29 01:55

要想成功改造,只需做到三点

  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,而非 CookiesessionIdCookie=com.pomer.test.servlet.MySimpleCookie#使用 Shiro 提供的 DefaultWebSessionManager,其维护自己的会话池,从而废弃服务器的会话池sessionManager=org.apache.shiro.web.session.mgt.DefaultWebSessionManagersessionIdCookie.name=Token#sessionIdCookie.domain=sishuok.com#sessionIdCookie.path=#sessionIdCookie.maxAge=1800sessionIdCookie.httpOnly=truesessionManager.sessionIdCookie=$sessionIdCookiesessionManager.sessionIdCookieEnabled=true#自定义会话 ID 生成器(SessionId 返回 JWT 串,而非随机 UUID)sessionIdGenerator=com.pomer.test.servlet.MySessionIdGenerator#如果考虑分布式服务器,可以自定义数据库存储会话 Dao,这里使用了内存存取会话sessionDAO=org.apache.shiro.session.mgt.eis.MemorySessionDAOsessionDAO.sessionIdGenerator=$sessionIdGeneratorsessionManager.sessionDAO=$sessionDAOsecurityManager.sessionManager=$sessionManager#以下为 JWT 无关配置,请忽略#声明 JdbcRealmjdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealmjdbcRealm.permissionsLookupEnabled=truejdbcRealm.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.DruidDataSourcedataSource.driverClassName=com.mysql.jdbc.DriverdataSource.url=jdbc:mysql://localhost:3306/web?useSSL=falsedataSource.username=webdataSource.password=123456jdbcRealm.dataSource=$dataSource#指定 securityManager 的 realms 实现securityManager.realms=$jdbcRealm#设置 urlauthc.loginUrl=/loginroles.unauthorizedUrl=/unauthorizedperms.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会话id2会话创建时间:Sat Sep 30 00:16:46 CST 2017会话id7228b82d-2520-4830-bb4f-d4cf450fe982会话创建时间:Sat Sep 30 00:16:56 CST 2017会话id4会话创建时间:Sat Sep 30 00:16:56 CST 2017会话id45f96994-3647-4aa1-8d67-a82c436c349f会话创建时间:Sat Sep 30 00:16:56 CST 2017会话id6会话创建时间:Sat Sep 30 00:16:56 CST 2017会话id:a3eea41d-311d-407b-9e5d-7491eaf229b4会话创建时间:Sat Sep 30 00:16:57 CST 2017会话id8会话创建时间:Sat Sep 30 00:16:57 CST 2017会话id3f45c24f-a1ab-462c-984d-c32060213bf8会话创建时间:Sat Sep 30 00:16:57 CST 2017会话id10会话创建时间:Sat Sep 30 00:16:57 CST 2017

提供参数,将 URL 改为 http://localhost:8080/shiro/?token=2

//可以看到会话得到维持会话id2会话创建时间:Sat Sep 30 00:16:46 CST 2017会话id2会话创建时间:Sat Sep 30 00:16:46 CST 2017会话id2会话创建时间:Sat Sep 30 00:16:46 CST 2017会话id2会话创建时间:Sat Sep 30 00:16:46 CST 2017会话id2会话创建时间:Sat Sep 30 00:16:46 CST 2017会话id2会话创建时间:Sat Sep 30 00:16:46 CST 2017会话id2会话创建时间:Sat Sep 30 00:16:46 CST 2017会话id2会话创建时间:Sat Sep 30 00:16:46 CST 2017
原创粉丝点击