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

How to use Shiro to realize login authentication and authority management in SpringBoot

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

Share

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

This article shows you how to use Shiro in SpringBoot to achieve login authentication and rights management, the content is concise and easy to understand, absolutely can make your eyes bright, through the detailed introduction of this article, I hope you can get something.

What is Shiro?

Apache Shiro is a powerful, flexible, open source security framework. It can neatly handle authentication, authorization, enterprise session management, and encryption.

The primary goal of Apache Shiro is to be easy to use and understand. Security is often complex and even painful, but this is not the case with Shiro. A good security framework should shield complexity and expose simple, intuitive API to simplify the time and effort developers spend implementing application security.

What can Shiro do?

Verify user identity

User access control, such as: 1, to determine whether the user is assigned a certain security role. 2. Determine whether the user is granted permission to complete an operation.

You can use Session API freely in a non-web or EJB container environment.

Can respond to authentication, access control, or events that occur in the Session lifecycle

One or more user security data sources can be combined into a composite user "view" (view)

Support for single sign-on (SSO) function

Support the provision of "Remember Me" service to obtain user association information without logging in

Wait-- all integrated into a cohesive, easy-to-use API.

Shiro strives to achieve these functions in all application environments, from command-line applications to enterprise applications, without the need for third-party frameworks, containers, application servers, and so on. Of course, the purpose of Shiro is to integrate into such an application environment as much as possible, but it can also be used out of the box in any environment other than them.

What are the components of Shiro?

Authentication (authentication), Authorization (authorization), Session Management (session management) and Cryptography (encryption) are called the four cornerstones of application security by the development team of Shiro framework. So let's take a look at them:

Authentication (authentication): user identification, often referred to as user "login"

Authorization (authorization): access control. For example, whether a user has permission to use an operation.

Session Management (session management): user-specific session management, even in non-web or EJB applications.

Cryptography (encryption): easy to use while encrypting the data source using an encryption algorithm.

There are other features to support and enhance security concerns in these different application environments. In particular, the following features are supported:

Web support: web provided by Shiro supports api, which makes it easy to secure web applications.

Caching: caching is an important means for Apache Shiro to ensure safe operation quickly and efficiently.

Concurrency: Apache Shiro supports the concurrency feature of multithreaded applications.

Testing: unit testing and integration testing are supported to ensure that the code is as secure as expected.

"Run As": this feature allows the user to assume the identity of another user (under permission).

"Remember Me": the identity of the user is recorded across the session, and login is required only if it is mandatory.

Note: Shiro does not maintain users or permissions, which need to be designed / provided by ourselves, and then injected into Shiro through the appropriate interface

Start with the code:

User (user) entity class creation, this example uses the Lombok plug-in to reduce the generation of GET/SET methods through the @ Data annotation.

@ Data@Entity@Table (name = "user") public class User {@ Id @ GeneratedValue (strategy = GenerationType.IDENTITY) private long id; private String username; private String password; private String salt; @ Column (name = "is_deleted", length = 2) private int isDeleted; / / deletion tag 0 has not been deleted 1 has been deleted @ Column (name = "gmt_create", updatable = false) private LocalDateTime createAt @ Column (name = "gmt_modified") private LocalDateTime updateAt; @ ManyToMany (fetch = FetchType.EAGER) @ JoinTable (name = "user_to_role", joinColumns = {@ JoinColumn (name = "user_id")}, inverseJoinColumns = {@ JoinColumn (name = "role_id")} private List roles; public String getCredentialsSalt () {return username + salt + salt;}}

The correspondence of the user corresponding role is declared as a many-to-many association, where the associated table entity can be viewed in the source code and ignored here.

Role (role) entity class creation:

@ Data@Entity@Table (name = "role") public class SysRole {@ Id @ GeneratedValue (strategy = GenerationType.IDENTITY) private long id; private String role; private String roleName; @ Column (name = "is_deleted", length = 2) private int isDeleted; / / Delete tag 0 has not been deleted 1 has been deleted @ CreatedDate @ Column (name = "gmt_create") private LocalDateTime createAt LastModifiedDate @ Column (name = "gmt_modified") private LocalDateTime updateAt; @ ManyToMany (fetch = FetchType.EAGER) @ JoinTable (name = "role_to_permission", joinColumns = {@ JoinColumn (name = "role_id")}, inverseJoinColumns = {@ JoinColumn (name = "perm_id")}) private List permissions;}

Permission (permission) entity class creation:

@ Data@Entity@Table (name = "permission") public class SysPermission {@ Id @ GeneratedValue (strategy = GenerationType.IDENTITY) private Integer id; private String code; private String name; @ Column (name = "is_deleted", length = 2) private int isDeleted; / / Delete tag 0 has not been deleted 1 has been deleted @ CreatedDate @ Column (name = "gmt_create") private LocalDateTime createAt @ LastModifiedDate @ Column (name = "gmt_modified") private LocalDateTime updateAt;}

This example uses JPA as the database persistence layer framework, so we leave the task of creating the table to the framework automatically, we just need to write the corresponding relationship clearly in entity. The struts.sql file given by the source code also details the DDL statement.

The focus of Shiro is on the configuration of the corresponding config file and the implementation of Realm.

How to implement ShiroConfig. In Shiro, shirFilter will filter the configured paths at the following levels:

/ * * shiro's built-in filter * anon: access the default without authentication * authc: must be authenticated to access * user: must have the function to remember me to access * perms: must have permission to access * role: have a role permission to access * ilter factory Set the corresponding filter condition and jump condition * / @ Configurationpublic class ShiroConfig {@ Bean public ShiroFilterFactoryBean shirFilter (DefaultWebSecurityManager securityManager) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean () ShiroFilterFactoryBean.setSecurityManager (securityManager); Map filterChainDefinitionMap = new HashMap (); shiroFilterFactoryBean.setLoginUrl ("/ login"); shiroFilterFactoryBean.setUnauthorizedUrl ("/ unauthorized"); shiroFilterFactoryBean.setSuccessUrl ("/ home/index"); filterChainDefinitionMap.put ("/ *", "anon"); filterChainDefinitionMap.put ("/ authorized/index", "authc"); filterChainDefinitionMap.put ("/ authorized/admin", "roles [admin]") FilterChainDefinitionMap.put ("/ authorized/add", "perms [Create,Update]"); filterChainDefinitionMap.put ("/ authorized/delete", "perms [Delete]"); shiroFilterFactoryBean.setFilterChainDefinitionMap (filterChainDefinitionMap); return shiroFilterFactoryBean;} @ Bean public HashedCredentialsMatcher hashedCredentialsMatcher () {HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher (); hashedCredentialsMatcher.setHashAlgorithmName (PasswordHelper.ALGORITHM_NAME) / / Hash algorithm hashedCredentialsMatcher.setHashIterations (PasswordHelper.HASH_ITERATIONS); / / number of hashes return hashedCredentialsMatcher;} / / inject your own realm @ Bean public CustomizedRealm shiroRealm () {CustomizedRealm shiroRealm = new CustomizedRealm (); shiroRealm.setCredentialsMatcher (hashedCredentialsMatcher ()); / / set the encryption method return shiroRealm } @ Bean public DefaultWebSecurityManager securityManager () {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager (); securityManager.setRealm (shiroRealm ()); return securityManager;} @ Bean public PasswordHelper passwordHelper () {return new PasswordHelper ();} / / add the use of annotations that will not take effect without this annotation @ Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor (DefaultWebSecurityManager securityManager) {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor () AuthorizationAttributeSourceAdvisor.setSecurityManager (securityManager); return authorizationAttributeSourceAdvisor;}}

Implementation of custom Realm:

Public class CustomizedRealm extends AuthorizingRealm {@ Autowired private UserService userService; / * Authorization * this method is called only when user permissions need to be detected, such as * @ param principals * @ return * / @ Override protected AuthorizationInfo doGetAuthorizationInfo (PrincipalCollection principals) {SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo (); String username = (String) principals.getPrimaryPrincipal () User user = userService.findUserByName (username); if (user = = null) return null; for (SysRole role: user.getRoles ()) {authorizationInfo.addRole (role.getRole ()); for (SysPermission permission: role.getPermissions ()) {authorizationInfo.addStringPermission (permission.getName ());}} return authorizationInfo } / * * Authentication * this method is used by default to verify whether the user name is correct or not, and an exception is thrown with an error. * @ param token * @ return * @ throws AuthenticationException * / @ Override protected AuthenticationInfo doGetAuthenticationInfo (AuthenticationToken token) throws AuthenticationException {String username = (String) token.getPrincipal (); User user = userService.findUserByName (username); if (user = = null) throw new AuthenticationException (ErrorCode.USER_NOT_FOUND.getMsg ()) SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo (user.getUsername (), user.getPassword (), ByteSource.Util.bytes (user.getCredentialsSalt ()), getName ()); return authenticationInfo;}}

Simple control layer logic:

@ RestController@RequestMapping@Slf4jpublic class UserController {@ Autowired private UserService userService; @ Autowired private PasswordHelper passwordHelper; @ GetMapping ("doLogin") public String login (@ RequestParam String username, @ RequestParam String password) {UsernamePasswordToken token = new UsernamePasswordToken (username, password); Subject subject = SecurityUtils.getSubject (); try {subject.login (token) } catch (IncorrectCredentialsException ice) {throw new AuthorizationException (ErrorCode.USER_PASSWORD_ERROR.getMsg ());} catch (UnknownAccountException uae) {throw new AuthorizationException (ErrorCode.IDENTIFICATION_ERROR.getMsg ());} / / Log in successfully and put user information in session User user = userService.findUserByName (username); subject.getSession () .setAttribute ("currentUser", user) Return "LOGIN SUCCEED";} @ GetMapping ("register") public String register (@ RequestParam String username, @ RequestParam String password) {User user = new User (); user.setUsername (username); user.setPassword (password); passwordHelper.encryptPassword (user); userService.saveUser (user); return "SUCCESS" } @ GetMapping ("test") @ RequiresRoles (value = {"USER"}) / / the USER role is required to access @ RequiresPermissions (value = {"QUERY", "ADD"}, logical = Logical.OR) / / the public String test (@ CurrentUser User user) {/ / @ CurrentUser custom annotation implementation of multiple permissions, please refer to CurrentUser.java The implementation process is log.info ("{}", user.getRoles ()) in the CurrentUserMethodArgumentResolver class. Return user.getUsername ();}}

In the above example, using the @ RequiresRoles annotation, you need to configure AuthorizationAttributeSourceAdvisor in ShiroConfig, otherwise the annotation will not take effect.

You can't fail without a demonstration:

1. We created a user, Zhang San, who has the permission of User, first by logging in; (if there is no user, you can call the register method to create the user first, and then configure the corresponding permission association relationship)

two。 There is a test method written here. At the beginning, we set the user permission to access successfully, as follows:

@ GetMapping ("test") @ RequiresRoles (value = {"USER"}) / / requires the USER role to access @ RequiresPermissions (value = {"QUERY", "ADD"}, logical = Logical.OR) / / multiple permissions public String test (@ CurrentUser User user) {/ / @ CurrentUser custom annotation implementation, please refer to CurrentUser.java. The implementation process is log.info ("{}", user.getRoles ()) in the CurrentUserMethodArgumentResolver class. Return user.getUsername ();} / @ RequiresRoles (value = {"USER"}) zhangsan has user permission and logged in successfully

There is no problem with permissions.

3. Modify the permission access to log in here to ADMIN level

@ GetMapping ("test") @ RequiresRoles (value = {"ADMIN"}) / / requires the ADMIN role to access @ RequiresPermissions (value = {"QUERY", "ADD"}, logical = Logical.OR) / / public String test (@ CurrentUser User user) {log.info ("{}", user.getRoles ()); return user.getUsername () } / / @ RequiresRoles (value = {"ADMIN"}) zhangsan does not have ADMIN permission and is blocked

The above content is how to use Shiro to achieve login authentication and rights management in SpringBoot. Have you learned any knowledge or skills? If you want to learn more skills or enrich your knowledge reserve, you are welcome to follow the industry information channel.

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