First look and then like, give yourself a little time to think, after thinking, please directly wechat search “Java learning way”, follow him. If you have suggestions for this article, please contact me on wechat: StudyJava

In actual projects, role permissions are often used to assign different rights and tasks to different roles. For example, ordinary users can only browse; Members can browse and comment; Super members can browse, comment and watch video classes, etc. There are many practical application scenarios. It is no exaggeration to say that almost every complete project is designed with access management in mind.

Therefore, in this article, Amiao shows you how to integrate Shiro permission framework into SpringBoot to achieve fast access management functions.

sequence

Generally speaking, Spring Security is the mainstream solution to manage permissions in Spring Boot. However, as long as Spring Security is too large and complex, most companies will choose Apache Shiro to use it as long as it can meet their business needs.

In general, the differences between Spring Security and Shiro are as follows:

Spring Security Apache Shiro
Heavyweight safety management framework Lightweight security management framework
Complex concepts and complex configurations Simple concept and configuration
powerful Features simple

This article will first take you through Apache Shiro, followed by a use case Demo.

Into the Apache Shiro

Official website of cognitive

As usual to the official website raking introduction:

Apache Shiro™ is a Powerful and Easy to Use Java Security Framework that performs authentication, authorization, Cryptography, and Session Management. With Shiro’s Easy-to-understand API, You can quickly and easily secure any application — from the smallest mobile applications to the largest Web and Enterprise Applications. Apache Shiro™ is a powerful and easy-to-use Java security framework for authentication, authorization, encryption, and session management. Shiro has an easy-to-understand API that allows you to quickly and easily access any application — from the smallest mobile applications to the largest web and enterprise applications.

In short, Apache Shiro is a powerful and flexible open source security framework that fully handles authentication, authorization, encryption, and session management.

What can Shiro really do?

  • Verifying user identity
  • Control user access rights, for example: 1. Determine whether a user is assigned a security role. 2. Check whether the user is granted the permission to perform an operation
  • You can use the Session API in any environment other than a Web or EJB container
  • It can respond to authentication, access control, or events that occur during the Session lifecycle
  • Combine one or more user security data sources into a composite user “view” (view)
  • Supports single sign-on (SSO)
  • Support to provide “Remember Me” service to obtain user association information without logging in

Why use Apache Shiro today?

The official explanation is detailed: shiro.apache.org/

The framework environment has changed a lot since 2003, so there are still good reasons to use Shiro today. There are actually many reasons. Apache Shiro is:

  • Ease of use – Ease of use is the ultimate goal of this project. Application security can be very confusing and frustrating, and seen as a “necessary evil.” If you make it easy to use so that novice programmers can start using it, you won’t have to suffer any more.
  • Comprehensive -Apache Shiro claims that there is no other security framework with breadth of scope, so it could be a “one-stop shop” for your security needs.
  • Flexible -Apache Shiro can work in any application environment. Although it can run in Web, EJB, and IoC environments, they are not required. Shiro also doesn’t require any specifications and doesn’t even have many dependencies.
  • Web Enabled -Apache Shiro has excellent Web application support, allowing you to create flexible security policies based on application urls and Web protocols such as REST, while also providing a set of JSP libraries to control page output.
  • Pluggable -Shiro’s clean APIS and design patterns make it easy to integrate with many other frameworks and applications. You’ll see Shiro seamlessly integrate with frameworks like Spring, Grails, Wicket, Tapestry, Mule, Apache Camel, Vaadin, and more.
  • Supported -Apache Shiro is part of the Apache Software Foundation, an organization that is proven to act in the best interest of its community. Project development and user community friendly citizens are always available to help. Commercial companies such as Katasoft can also provide professional support and services if required.

Shiro core concepts

Apache Shiro is a comprehensive, feature-rich security framework.

The following is a block diagram describing Shiro’s capabilities:

As shown in the figure, the functions include:

  • Authentication: User identification, often referred to as user “login”
  • Authorization: Access control. For example, whether a user has the permission to use an operation.
  • Session Management: User-specific Session Management, even in non-Web or EJB applications.
  • Cryptography: Ensures ease of use while encrypting data sources using encryption algorithms.

Shiro also adds additional features to support and reinforce security concerns in these different application environments.

In particular, the following features are supported:

  • Web support: Shiro provides a Web support API that makes it easy to secure Web applications.
  • Caching: Caching is an important tool for Apache Shiro to ensure fast and efficient security operations.
  • Concurrency: Apache Shiro supports concurrency features for multi-threaded applications.
  • Testing: Support for unit and integration testing to ensure code is as secure as expected.
  • “Run As” : This feature allows users to assume the identity of another user (with permission).
  • “Remember Me” : Records the identity of the user across sessions, logging in only when mandatory.

Note: Shiro does not maintain users or permissions, which we design/provide and inject into Shiro through the appropriate interface

Use Case Demo

1. Create a Maven project

To help us initialize the project, Spring Boot provides us with a project template generation site.

  • 1. Open your browser and go to start.spring. IO /
  • 2, according to the page prompts, select building tools, development language, project information, etc.

2. Import the springBoot parent dependency

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.0.2. RELEASE</version>
</parent>
Copy the code

3. Related JAR packages

The web package

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Copy the code

The Shro-Spring package is the heart of this article

<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-spring</artifactId>
	<version>1.4.0</version>
</dependency>Shiro annotations use AOP<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>Database related packages use MybatisPlus<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid</artifactId>
	<version>1.1.12</version>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-boot-starter</artifactId>
	<version>3.1.0</version>
</dependency>
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-generator</artifactId>
	<version>3.1.0</version>
</dependency>
	<dependency>
	<groupId>org.apache.velocity</groupId>
	<artifactId>velocity-engine-core</artifactId>
	<version>2.0</version>
</dependency>
Copy the code

4. The database

The construction sentences are in the project, the project address: github.com/mmzsblog/mm…

5. Customize the Realm

public class MyShiroRealm extends AuthorizingRealm {
	@Autowired
	private UserService userService;
	@Autowired
	private RoleService roleService;
	@Autowired
	private PermissionService permissionService;

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		// HttpServletRequest request = (HttpServletRequest) ((WebSubject) SecurityUtils
		// .getSubject()).getServletRequest(); // This can be used to obtain additional parameter information submitted at login time
		String username = (String) principals.getPrimaryPrincipal();
		// Accept permission
		/ / role
		Set<String> roles = new HashSet<String>();
		Role role = roleService.getRoleByUserName(username);
		System.out.println(role.getRoleName());
		roles.add(role.getRoleName());
		authorizationInfo.setRoles(roles);
		/ / permission
		Set<String> permissions = new HashSet<String>();
		List<Permission> querypermissions = permissionService.getPermissionsByRoleId(role.getId());
		for (Permission permission : querypermissions) {
			permissions.add(permission.getPermissionName());
		}
		authorizationInfo.setStringPermissions(permissions);
		return authorizationInfo;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
			throws AuthenticationException {
		String loginName = (String) authcToken.getPrincipal();
		// Get the user password
		User user = userService.getOne(new QueryWrapper<User>().eq("username", loginName));
		if (user == null) {
			// No account found
			throw new UnknownAccountException();
		}
		String password = new String((char[]) authcToken.getCredentials());
		String inpass = (new Md5Hash(password, user.getUsername())).toString();
		if(! user.getPassword().equals(inpass)) {throw new IncorrectCredentialsException();
		}
		// Give AuthenticatingRealm the password match using CredentialsMatcher
		SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(loginName, user.getPassword(),
				ByteSource.Util.bytes(loginName), getName());

		returnauthenticationInfo; }}Copy the code

6. Shiro configuration class

@Configuration
public class ShiroConfiguration {
	private static final Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class);

	/** * Shiro's Web filter Factory is named shiroFilter */
	@Bean(name = "shiroFilter")
	public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		// Shiro's core security interface, this property is required
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		// Requests that require permissions, if not logged in will be redirected to the URL set here
		shiroFilterFactoryBean.setLoginUrl("/login.html");
		// Set the redirect URL after successful login
		shiroFilterFactoryBean.setSuccessUrl("/main.html");
		// Set the no permission redirect interface. This interface does not take effect and is usually a custom exception
		shiroFilterFactoryBean.setUnauthorizedUrl("/error.html");
		Map<String, Filter> filterMap = new LinkedHashMap<>();
		// filterMap.put("authc", new AjaxPermissionsAuthorizationFilter());
		shiroFilterFactoryBean.setFilters(filterMap);
		Shiro filter chain Map structure defined / * * * in the Map key (XML) refers to the value value in the first '/' on behalf of the path is relative to it. The getContextPath () value to * anon: The corresponding filter is empty and does nothing, so the * after.do and.jsp is the parameter, for example login.jsp? Page under the main this * authc: the filter must be validated before they can visit, it is Shiro built-in an interceptor org.. Apache Shiro. Web. Filter. Authc. * FormAuthenticationFilter * /
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		/** Filter chain definition, executed from top to bottom, usually put /** at the bottom; Authc: All urls must be authenticated to be accessible; * anon: All urls can be accessed anonymously */
		filterChainDefinitionMap.put("/login.html"."authc");
		filterChainDefinitionMap.put("/login"."anon");
		filterChainDefinitionMap.put("/js/**"."anon");
		filterChainDefinitionMap.put("/css/**"."anon");
		filterChainDefinitionMap.put("/logout"."logout");
		filterChainDefinitionMap.put("/ * *"."authc");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}

	/** * Permission management */
	@Bean
	public SecurityManager securityManager(a) {
		logger.info("=======================shiro=======================");
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(MyShiroRealm());
		// securityManager.setRememberMeManager(rememberMeManager);
		return securityManager;
	}

	/** * Shiro Realm inherits from AuthorizingRealm's custom Realm by specifying that Shiro validates the user login class as a custom */
	@Bean
	public MyShiroRealm MyShiroRealm(a) {
		MyShiroRealm userRealm = new MyShiroRealm();
		userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
		return userRealm;
	}

	/** * credential verifier password authentication */
	@Bean(name = "credentialsMatcher")
	public HashedCredentialsMatcher hashedCredentialsMatcher(a) {
		HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
		// Hash algorithm: MD5 algorithm is used here;
		hashedCredentialsMatcher.setHashAlgorithmName("md5");
		// The number of hashes, such as hashes twice, equals md5(MD5 (""));
		hashedCredentialsMatcher.setHashIterations(1);
		/ / storedCredentialsHexEncoded default is true, this time using password encryption with Hex code; If false, use Base64 encoding
		hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
		return hashedCredentialsMatcher;
	}

	/** * Turn on Shiro's annotations (e.g@RequiresRoles.@RequiresPermissions), using SpringAOP to scan classes using Shiro annotations and perform security logic validation if necessary */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(a) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
		returnauthorizationAttributeSourceAdvisor; }}Copy the code

7. The test class

@RestController
public class UserController {
	@PostMapping("login")
	public String name(String username, String password) {
		String result = "Logged in";
		Subject currentUser = SecurityUtils.getSubject();
		UsernamePasswordToken token = new UsernamePasswordToken(username, password);
		if(! currentUser.isAuthenticated()) {try {
				currentUser.login(token);/ / triggers com. Shiro. Config. MyShiroRealm doGetAuthenticationInfo method
				result = "Login successful";
			} catch (UnknownAccountException e) {
				result = "User name error";
			} catch (IncorrectCredentialsException e) {
				result = "Password error"; }}return result;
	}

	@GetMapping("logout")
	public void logout(a) {
		Subject currentUser = SecurityUtils.getSubject();
		currentUser.logout();
	}

	@RequiresPermissions("role:update")
	@GetMapping("/role")
	public String name(a) {
		return "hello";
	}

	@RequiresPermissions("user:select")
	@GetMapping("/role2")
	public String permission(a) {
		return "hello sel"; }}Copy the code

7.1 Login Test

Database account (password encrypted with MD5 salt)

7.2 Permission Testing

8. That

8.1 Treatment in case of limitation of authority

An exception was customized at unauthorized time. Therefore, when a permission test is performed, the configured message “No permission” is displayed.

@ControllerAdvice
public class ShiroException {
	@ExceptionHandler(value = UnauthorizedException.class)
	@ResponseBody
	public String name(a) {
		return "No access"; }}Copy the code

8.2 Testing Role Rights The same as testing role rights

Permission Settings can be set in the Shiro filter chain in the Shiro configuration class or in annotation mode, which is used in this article.

8.3 Shiro’s Session and Cache

Shiro session and cache management can be customized, this article uses the default, recommended to customize, convenient management.

summary

  • Apache Shiro is a security framework for Java
  • Shiro is a powerful, easy-to-use Java security framework for easier authentication, authorization, encryption, session management, Web integration, caching, and more
  • Shiro is small and simple to use
  • Spring includes Spring Security, a permissions framework that relies too closely on Spring and is not as easy to use as Shiro.
  • Shiro does not depend on Spring, Shiro can not only realize the permission management of Web applications, but also realize the C/S system, distributed system permission management,
  • Shiro is a lightweight framework, and more and more enterprise projects are using Shiro.

Reference: www.cnblogs.com/joker-dj/ar…

I am Amiao, and your [Sanlian] is the biggest motivation for amiao’s creation. If there are any mistakes or suggestions in this blog, please leave a comment!

The article is constantly updated, you can search “The way of Java learning” on wechat to read it in the first time, reply [666] I prepared the necessary e-book programmer + more than hd teaching videos, as well as surprise interview questions, welcome to pick up.