Springboot+shiro+jwt

Source: Internet
Author: User
Tags getmessage

Jwtutil

We use JWT's tool class to generate our tokens, a tool class that has two ways to generate tokens and check tokens.

When generating tokens, specify token expiration time EXPIRE_TIME and signing key SECRET , then write date and username to token, and sign with the HS256 signature algorithm with the key

Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);Algorithm algorithm = Algorithm.HMAC256(SECRET);JWT.create()    .withClaim("username", username)    //到期时间    .withExpiresAt(date)    //创建一个新的JWT,并使用给定的算法进行标记    .sign(algorithm);
Database tables

Role: Character; permission: permission; ban: Seal number status

Each user has a corresponding role (user,admin), Permissions (NORMAL,VIP), and the user role default permissions are normal, Admin role default permissions are VIP (of course, user can also be VIP)

Filter filters

In the previous article, we used the Shiro default permission intercept filter, and because of the integration of JWT, we need to customize our own filters Jwtfilter,jwtfilter inherit Basichttpauthenticationfilter, And part of the original method was rewritten

The filter has three main steps:

  1. Verify that the request header has token((HttpServletRequest) request).getHeader("Token") != null
  2. If there is token, execute the login () method of Shiro, submit token to Realm for inspection, if there is no token, indicate the current status is visitor status (or some other interface that does not require authentication)

     @Overrideprotected boolean isaccessallowed (ServletRequest request, servletresponse response, Object Mappedvalue Throws Unauthorizedexception {//determines if the requested header is with "token" if (((httpservletrequest) request). GetHeader ("token")! = nul L) {//If present, enter the Executelogin method to perform the login, check that the token is correct try {executelogin (request, response); return true; } catch (Exception e) {//token error Responseerror (response, E.getmessage ()); }}//If the request header does not have token, it may be a login operation or visitor state access, without checking tokens, directly returning true return true;} @Overrideprotected boolean executelogin (ServletRequest request, servletresponse response) throws Exception {Httpservle Trequest httpservletrequest = (httpservletrequest) request; String token = Httpservletrequest.getheader ("token"); Jwttoken Jwttoken = new Jwttoken (token); Submit to Realm for login, and if wrong he throws an exception and is captured Getsubject (request, response). Login (Jwttoken); If no exception is thrown, the login succeeds, return true return true;} 
  3. If an error occurs during token validation, such as a token check failure, then I will treat the request as if authentication does not pass, then redirect to/unauthorized/**

In addition, I put cross-domain support in the filter to handle

Realm class

It's still our custom Realm, and for this piece you can read my previous article on Shiro.

  • Identity verification

    if (username == null || !JWTUtil.verify(token, username)) {throw new AuthenticationException("token认证失败!");}String password = userMapper.getPassword(username);if (password == null) {throw new AuthenticationException("该用户不存在!");}int ban = userMapper.checkUserBanStatus(username);if (ban == 1) {throw new AuthenticationException("该用户已被封号!");}

    Get the token, check if token is valid, whether the user exists, and the user's seal number

  • Authority authentication
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//获得该用户角色String role = userMapper.getRole(username);//每个角色拥有默认的权限String rolePermission = userMapper.getRolePermission(username);//每个用户可以设置新的权限String permission = userMapper.getPermission(username);Set<String> roleSet = new HashSet<>();Set<String> permissionSet = new HashSet<>();//需要将 role, permission 封装到 Set 作为 info.setRoles(), info.setStringPermissions() 的参数roleSet.add(role);permissionSet.add(rolePermission);permissionSet.add(permission);//设置该用户拥有的角色和权限info.setRoles(roleSet);info.setStringPermissions(permissionSet);

    Using tokens obtained in the username, from the database to find the user's own roles, permissions, stored in Simpleauthorizationinfo

Shiroconfig Configuration Class

Set up our custom filter and make all requests through our filters, in addition to those we use to process unauthenticated requests/unauthorized/**

@Beanpublic ShiroFilterFactoryBean factory(SecurityManager securityManager) {    ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();    // 添加自己的过滤器并且取名为jwt    Map<String, Filter> filterMap = new HashMap<>();    //设置我们自定义的JWT过滤器    filterMap.put("jwt", new JWTFilter());    factoryBean.setFilters(filterMap);    factoryBean.setSecurityManager(securityManager);    Map<String, String> filterRuleMap = new HashMap<>();    // 所有请求通过我们自己的JWT Filter    filterRuleMap.put("/**", "jwt");    // 访问 /unauthorized/** 不通过JWTFilter    filterRuleMap.put("/unauthorized/**", "anon");    factoryBean.setFilterChainDefinitionMap(filterRuleMap);    return factoryBean;}
Permission control annotation @RequiresRoles, @RequiresPermissions

These two annotations are for our main permission control annotations, such as

// 拥有 admin 角色可以访问@RequiresRoles("admin")
// 拥有 user 或 admin 角色可以访问@RequiresRoles(logical = Logical.OR, value = {"user", "admin"})
// 拥有 vip 和 normal 权限可以访问@RequiresPermissions(logical = Logical.AND, value = {"vip", "normal"})
// 拥有 user 或 admin 角色,且拥有 vip 权限可以访问@GetMapping("/getVipMessage")@RequiresRoles(logical = Logical.OR, value = {"user", "admin"})@RequiresPermissions("vip")public ResultMap getVipMessage() {    return resultMap.success().code(200).message("成功获得 vip 信息!");}

When we write the interface has the above annotations, if the request does not have token or with token but the permission authentication does not pass, it will report unauthenticatedexception exception, but I am in Exceptioncontroller Class handles these exceptions in a centralized

@ExceptionHandler(ShiroException.class)public ResultMap handle401() {    return resultMap.fail().code(401).message("您没有权限访问!");}

At this point, a Shiro-related exception is returned

{    "result": "fail",    "code": 401,    "message": "您没有权限访问!"}

In addition to the above two types, there are @RequiresAuthentication, @RequiresUser and other annotations

function implementation

User roles are divided into three categories, admin admin, normal user, visitor guest;admin default permission is vip,user default permission is normal, when user upgrade to VIP permissions, you can access the VIP permissions of the page.

The implementation can see the source code (the address is given at the beginning)

Landing

Login interface without token, when the login password, the user name verification is correct after returning token.

@PostMapping("/login")public ResultMap login(@RequestParam("username") String username,                       @RequestParam("password") String password) {    String realPassword = userMapper.getPassword(username);    if (realPassword == null) {        return resultMap.fail().code(401).message("用户名错误");    } else if (!realPassword.equals(password)) {        return resultMap.fail().code(401).message("密码错误");    } else {        return resultMap.success().code(200).message(JWTUtil.createToken(username));    }}
{    "result": "success",    "code": 200,    "message": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjUxODQyMzUsInVzZXJuYW1lIjoiaG93aWUifQ.fG5Qs739Hxy_JjTdSIx_iiwaBD43aKFQMchx9fjaCRo"}
Exception handling
    // 捕捉shiro的异常    @ExceptionHandler(ShiroException.class)    public ResultMap handle401() {        return resultMap.fail().code(401).message("您没有权限访问!");    }    // 捕捉其他所有异常    @ExceptionHandler(Exception.class)    public ResultMap globalException(HttpServletRequest request, Throwable ex) {        return resultMap.fail()                .code(getStatus(request).value())                .message("访问出错,无法访问: " + ex.getMessage());    }
Permission control
    • Usercontroller (user or admin can access)
      On the interface.@RequiresRoles(logical = Logical.OR, value = {"user", "admin"})

      • VIP Privileges
        Plus@RequiresPermissions("vip")
    • Admincontroller (Admin can access)
      On the interface.@RequiresRoles("admin")

    • Guestcontroller (Everyone can access)
      Do not do permission handling
Test results

Springboot+shiro+jwt

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.