shiro 字段不是username 和password_Shiro整合JWT

Shiro提供了完整的企业级会话管理功能,不依赖于底层容器Tomcat等,即直接使用Shiro的会话管理可以直接替换如Web容器的会话管理.

会话

所谓会话,即用户访问应用时保持的连接关系,在多次交互中应用能够识别出当前访问的用户是谁,且可以在多次交互中保存一些数据。如访问一些网站时登录成功后,网站可以记住用户,且在退出之前都可以识别当前用户是谁。

Shiro是基于Session管理权限,应用单体项目可以,但是前后端分离的项目需要增加单点登录功能不可能使用 session 的方式进行鉴权,所以 JWT 就被派上了用场,可以通过一个加密token来进行前后端的鉴权。

1 增加pom.xml

<dependency>    <groupId>com.auth0groupId>    <artifactId>java-jwtartifactId>dependency>

2 增加状态码定义

/** * 定义的静态编码 */public final class AppCode {    public static final String SUCESS = "200";    public static final String UNAUTHENTICATED = "401";    public static final String UNAUTHORIZED = "403";    public static final String NOT_FOUND = "404";    public static final String ERROR = "500";}

3 增加JwtUtils.java工具类

package com.wei.utils.jwt;import com.auth0.jwt.JWT;import com.auth0.jwt.JWTVerifier;import com.auth0.jwt.algorithms.Algorithm;import com.auth0.jwt.exceptions.JWTDecodeException;import com.auth0.jwt.exceptions.JWTVerificationException;import com.auth0.jwt.interfaces.DecodedJWT;import java.util.Date;public class JwtUtils {    private static final long EXPIRE_TIME = 1 * 60 * 1000;    private static final String CLAIM_NAME = "username";    public static String createToken(String username, String password) {        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);        //加密处理密码        Algorithm algorithm = Algorithm.HMAC256(password);        return JWT.create()                .withClaim(CLAIM_NAME, username)                .withExpiresAt(date)                .sign(algorithm);    }    public static boolean verify(String username, String dbPwd, String token) {        Algorithm algorithm = Algorithm.HMAC256(dbPwd);        JWTVerifier jwtVerifier = JWT.require(algorithm)                .withClaim(CLAIM_NAME, username).build();        try {            jwtVerifier.verify(token);        } catch (JWTVerificationException e) {            return false;        }        return true;    }    public static String getUserName(String token) {        try {            DecodedJWT jwt = JWT.decode(token);            return jwt.getClaim(CLAIM_NAME).asString();        } catch (JWTDecodeException e) {            return null;        }    }}

4 增加JwtToken包装类

package com.wei.web.shiro.jwt;import org.apache.shiro.authc.HostAuthenticationToken;public class JwtToken implements HostAuthenticationToken {    private String username;    private char[] password;    private String host;    private String token;    public JwtToken(String token) {        this.token = token;    }    public JwtToken(String username, char[] password) {        this(username, password, (String) null);    }    public JwtToken(String username, String password) {        this(username, (char[]) (null != password ? password.toCharArray() : null), (String) null);    }    public JwtToken(String username, char[] password, String host) {        this.username = username;        this.password = password;        this.host = host;    }    @Override    public String getHost() {        return host;    }    @Override    public Object getPrincipal() {        return this.getToken();    }    @Override    public Object getCredentials() {        return this.getToken();    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public char[] getPassword() {        return password;    }    public void setPassword(char[] password) {        this.password = password;    }    public void setHost(String host) {        this.host = host;    }    public String getToken() {        return token;    }    public void setToken(String token) {        this.token = token;    }}

5 增加JwtFilter继承BasicHttpAuthenticationFilter

public class JwtFilter extends BasicHttpAuthenticationFilter {    private static final Logger LOGGER = LoggerFactory.getLogger(JwtFilter.class);    private static final String AUTHZ_HEADER = "token";    private static final String CHARSET = "UTF-8";    /**     * 处理未经验证的请求     */    @Override    protected boolean onAccessDenied(ServletRequest request, ServletResponse response)            throws Exception {        boolean loggedIn = false;        if (this.isLoginAttempt(request, response)) {            loggedIn = this.executeLogin(request, response);        }        if (!loggedIn) {            this.sendChallenge(request, response);        }        return loggedIn;    }    /**     * 请求是否已经登录(携带token)     */    @Override    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {        String authzHeader = WebUtils.toHttp(request).getHeader(AUTHZ_HEADER);        return authzHeader != null;    }    /**     * 执行登录方法(由自定义realm判断,吃掉异常返回false)     */    @Override    protected boolean executeLogin(ServletRequest request, ServletResponse response)            throws Exception {        String token = WebUtils.toHttp(request).getHeader(AUTHZ_HEADER);        if (null == token) {            String msg = "executeLogin method token must not be null";            throw new IllegalStateException(msg);        }        //交给realm判断是否有权限,没权限返回false交给onAccessDenied        JwtToken jwtToken = new JwtToken(token);        try {            this.getSubject(request, response).login(jwtToken);            return true;        } catch (AuthenticationException e) {            return false;        }    }    /**     * 构建未授权的请求返回,filter层的异常不受exceptionAdvice控制,这里返回401,把返回的json丢到response中     */    @Override    protected boolean sendChallenge(ServletRequest request, ServletResponse response) {        HttpServletResponse httpResponse = WebUtils.toHttp(response);        String contentType = "application/json;charset=" + CHARSET;        httpResponse.setStatus(Integer.parseInt(AppCode.UNAUTHENTICATED));        httpResponse.setContentType(contentType);        try {            String msg = "对不起,您无权限进行操作!";            ResultVo resultVo = new ResultVo(AppCode.UNAUTHENTICATED,msg,"");            JsonMapper mapper = new JsonMapper();            PrintWriter printWriter = httpResponse.getWriter();            printWriter.append(mapper.writeValueAsString(resultVo));//      byte[] data = unauthentication.toString().getBytes(CHARSET);//      OutputStream outputStream = httpResponse.getOutputStream();//      outputStream.write(data);        } catch (IOException e) {            LOGGER.error("sendChallenge error,can not resolve httpServletResponse");        }        return false;    }    /**     * 请求前处理,处理跨域     */    @Override    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {        HttpServletRequest httpServletRequest = (HttpServletRequest) request;        HttpServletResponse httpServletResponse = (HttpServletResponse) response;        httpServletResponse                .setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");        httpServletResponse.setHeader("Access-Control-Allow-Headers",                httpServletRequest.getHeader("Access-Control-Request-Headers"));        // 跨域时,option请求直接返回正常状态        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {            httpServletResponse.setStatus(HttpStatus.OK.value());            return false;        }        return super.preHandle(request, response);    }}

6 修改ShiroRealm对象,修改认证与鉴权方法,并增加supports方法

/** * 设置realm支持的authenticationToken类型 */@Overridepublic boolean supports(AuthenticationToken token){    return null != token && token instanceof JwtToken;}//JWT授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)        throws AuthenticationException{    String token = principalCollection.toString();    //根据token获取权限授权    String code = JwtUtils.getUserName(token);    //可以根据获取的人员信息赋值权限    Employee employee = employeeService.getEmployeeByCode(code);    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();    authorizationInfo.addRole(AppPermission.ADMIN);    //authorizationInfo.setRoles(employee.getRoles());    //authorizationInfo.setStringPermissions(employee.getPermissions());    return authorizationInfo;}/** * 登陆认证 * * @param authenticationToken jwtFilter传入的token * @return 登陆信息 * @throws AuthenticationException 未登陆抛出异常 */@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)        throws AuthenticationException {    //getCredentials getPrincipal getToken 都是返回jwt生成的token串    String token = (String) authenticationToken.getCredentials();    String code = JwtUtils.getUserName(token);    if (code == null) {        return null;    }    Employee employee = employeeService.getEmployeeByCode(code);    if(employee==null){        return null;    }    if (!JwtUtils.verify(code, employee.getPassword(), token)) {        return null;    }    return new SimpleAuthenticationInfo(token, token, getName());}

6 修改ShiroConfig对象,只需要在设置ShiroFilterFactoryBean对象将JWTFilter对象加入到shiroFilterFactoryBean中即可

filters.put("authc", new JwtFilter());

f3a7b690b62464d24c7c4a66666ca83a.png

7 修改登录/登出的方法

@Overridepublic String login(String code, String password){    AssertUtils.notEmpty(code,"用户名不能为空!");    AssertUtils.notEmpty(password,"密码不能为空!");    Employee employee = getEmployeeByCode(code);    if(employee==null){        return "";    }    if(password.equals(employee.getPassword())){        return JwtUtils.createToken(code,password);    }    return "";}@Overridepublic boolean logout() {    Subject subject = SecurityUtils.getSubject();    subject.logout();    return true;}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值