Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Springboot+shiro+jwt

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/03 Report--

JWTUtil

We use the tool class of JWT to generate our token, which mainly has two methods: generating token and verifying token

When generating token, specify the token expiration time EXPIRE_TIME and signature key SECRET, then write date and username to token and sign using 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) / / Expiration time .withExpiresAt (date) / / create a new JWT and mark it with the given algorithm .sign (algorithm); database table

Role: role; permission: permission; ban: blocked status

Each user has a corresponding role (user,admin) and permission (normal,vip), while the default permission for the user role is normal, and the default permission for the admin role is vip (of course, user can also be vip)

Filter

In the previous article, we used shiro's default permission to intercept Filter, but because of the integration of JWT, we need to customize our own filter JWTFilter,JWTFilter inherits BasicHttpAuthenticationFilter, and some of the original methods are overridden

The filter has three main steps:

Verify whether the request header has token ((HttpServletRequest) request) .getHeader ("Token")! = null

If there is token, execute the login () method of shiro, and submit the token to Realm for verification; if there is no token, the current status is tourist status (or other APIs that do not require authentication)

@ Overrideprotected boolean isAccessAllowed (ServletRequest request, ServletResponse response, Object mappedValue) throws UnauthorizedException {/ / determine whether the request header of the request is marked with "Token" if (HttpServletRequest) request) .getHeader ("Token")! = null) {/ / if it exists, log in to the executeLogin method and check whether token is correct try {executeLogin (request, response); return true } catch (Exception e) {/ / token error responseError (response, e.getMessage ();}} / / if the request header does not exist Token, it may be a login operation or a visitor status visit. Without checking token, directly return true return true;} @ Overrideprotected boolean executeLogin (ServletRequest request, ServletResponse response) throws Exception {HttpServletRequest httpServletRequest = (HttpServletRequest) request String token = httpServletRequest.getHeader ("Token"); JWTToken jwtToken = new JWTToken (token); / / submitted to realm for login. If there is an error, he will throw an exception and be caught getSubject (request, response) .login (jwtToken); / / if no exception is thrown, login is successful and true return true is returned } if an error occurs during token verification, such as token verification failure, then I will treat the request as an authentication failure and redirect to / unauthorized/**

In addition, I put cross-domain support into this filter to handle

Realm class

It is still our custom Realm. For those who don't know this yet, you can take a look at my last shiro article first.

Identity authentication

If (username = = null | |! JWTUtil.verify (token, username)) {throw new AuthenticationException ("token authentication failed!") ;} String password = userMapper.getPassword (username); if (password = = null) {throw new AuthenticationException ("this user does not exist!") ;} int ban = userMapper.checkUserBanStatus (username); if (ban = = 1) {throw new AuthenticationException ("this user has been blocked!") ;}

Get the incoming token and check whether the token is valid, whether the user exists, and whether the user's name is sealed.

Authorization SimpleAuthorizationInfo info = new SimpleAuthorizationInfo (); / / obtain the user role String role = userMapper.getRole (username); / / each role has the default permission String rolePermission = userMapper.getRolePermission (username); / / each user can set new permissions String permission = userMapper.getPermission (username); Set roleSet = new HashSet (); Set permissionSet = new HashSet (); / / need to encapsulate role and permission into Set as parameters roleSet.add (role) of info.setRoles () and info.setStringPermissions () PermissionSet.add (rolePermission); permissionSet.add (permission); / / set the roles and permissions that the user has info.setRoles (roleSet); info.setStringPermissions (permissionSet)

Use the username obtained in token to find out the roles and permissions owned by the user from the database and store them in SimpleAuthorizationInfo.

ShiroConfig configuration class

Set up our custom filter and pass all requests through our filter, except for the / unauthorized/** that we use to handle unauthenticated requests

@ Beanpublic ShiroFilterFactoryBean factory (SecurityManager securityManager) {ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean (); / / add your own filter and name it jwt Map filterMap = new HashMap (); / / set our custom JWT filter filterMap.put ("jwt", new JWTFilter (); factoryBean.setFilters (filterMap); factoryBean.setSecurityManager (securityManager); Map filterRuleMap = new HashMap ()) / / all requests are made through our own JWTFilter filterRuleMap.put ("/ * *", "jwt"); / / access / unauthorized/** does not go through JWTFilter filterRuleMap.put ("/ unauthorized/**", "anon"); factoryBean.setFilterChainDefinitionMap (filterRuleMap); return factoryBean;} permission control annotations @ RequiresRoles, @ RequiresPermissions

These two annotations are our main access control annotations, such as

/ / have admin roles to access @ RequiresRoles ("admin") / / have user or admin roles to access @ RequiresRoles (logical = Logical.OR, value = {"user", "admin"}) / / have vip and normal permissions to access @ RequiresPermissions (logical = Logical.AND, value = {"vip", "normal"}) / / have user or admin roles And with vip permission, you can visit @ GetMapping ("/ getVipMessage") @ RequiresRoles (logical = Logical.OR, value = {"user", "admin"}) @ RequiresPermissions ("vip") public ResultMap getVipMessage () {return resultMap.success (). Code (200). Message ("successfully get vip information!") ;}

When the API we write has the above comments, if the request does not have token or token but the permission authentication fails, a UnauthenticatedException exception will be reported, but I have handled these exceptions centrally in the ExceptionController class.

@ ExceptionHandler (ShiroException.class) public ResultMap handle401 () {return resultMap.fail () .code (401) .message ("you do not have permission to access!") ;}

In this case, a shiro-related exception will be returned

{"result": "fail", "code": 401, "message": "you do not have permission to access!" }

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

Function realization

User roles are divided into three categories: administrator admin, ordinary user user. The default permission for visitor guest;admin is vip,user. The default permission is normal. When user is upgraded to vip permission, you can access the page with vip permission.

The specific implementation can be found in the source code (address has been given at the beginning)

Landing

The login interface does not have token. When the login password and user name are verified correctly, return 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 ("user name error") } else if (! realPassword.equals (password)) {return resultMap.fail (). Code (401). Message ("password error");} else {return resultMap.success (). Code (200) .message (JWTUtil.createToken (username)) } {"result": "success", "code": 200,200, "message": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjUxODQyMzUsInVzZXJuYW1lIjoiaG93aWUifQ.fG5Qs739Hxy_JjTdSIx_iiwaBD43aKFQMchx9fjaCRo"} exception handling / / catching shiro exception @ ExceptionHandler (ShiroException.class) public ResultMap handle401 () {return resultMap.fail () .code (401) .message ("you do not have permission to access!") ;} / / catch all other exceptions @ ExceptionHandler (Exception.class) public ResultMap globalException (HttpServletRequest request, Throwable ex) {return resultMap.fail () .code (getStatus (request). Value ()) .message ("access error, unable to access:" + ex.getMessage ());} permission control

UserController (accessible by user or admin)

Put @ RequiresRoles on the interface (logical = Logical.OR, value = {"user", "admin"})

Vip permission

Plus @ RequiresPermissions ("vip")

AdminController (accessible by admin)

Put @ RequiresRoles ("admin") on the interface

GuestController (accessible to all)

Do not do permissions to deal with test results

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report