In addition to oauth and shiro, we learn oauth 2.0 here
1.1
Authentication and authorization are two basic concepts to solve software system security. Authentication is to verify whether the user's identity is legal, and authorization is to verify whether the user has the authority to operate resources. The development of Internet also promotes the progress of software open design. Software should be open and safe. How to use a unified solution to solve the authentication requirements of software itself and external systems is a problem to be considered in current Internet applications. OAuth2.0 protocol is the current open and popular authentication protocol. This course uses the popular spring The security authentication framework and OAuth2.0 protocol realize the authentication and authorization technology solutions of single and distributed systems.
1.2
What is certification
What is authorization
1.3 what is conversation
After the user passes the authentication, in order to avoid every operation of the user needing authentication, we put the user's login information in the drawing. The session is the mechanism provided by the system to ensure the user's login page status. The common methods are session based and token based
The difference between session and token:
a. session needs to put the data in the cookie. token does not need to be put in the cookie, but also in the localStorage
b. Based on the session, the server stores the session, while the token server does not need to store, but verifies whether the token sent by the client is correct
1.4 authorized data model
Authorization can be understood as who's how to operate what (which), i.e. what kind of resources and how to operate those users
1.5.1 how to authorize:
2. session based authentication method:
Here's the actual battle: first, you can write a session based authentication login to familiarize yourself with the process, and then you can use spring based security to authenticate and authorize
pom file
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.xiaofeifei.security</groupId> <artifactId>security-springmvc</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>5.1.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.1.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.8</version> </dependency> </dependencies> <build> <finalName>securityspringmvc</finalName> <pluginManagement> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>9090</port> <path>/</path> <server>tomcat7</server> <ignorePackaging>true</ignorePackaging> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <artifactId>maven-resources-plugin</artifactId> <configuration> <encoding>utf-8</encoding> <useDefaultDelimiters>true</useDefaultDelimiters> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> <includes> <include>**/*</include> </includes> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> </resources> </configuration> </plugin> </plugins> </pluginManagement> </build> </project>
We use servlet 3.0, so many configurations are not configured in config. We directly configure them in java classes, and web.xml We all configure in java classes
Basic knowledge:
spring containers are applicationContext.xml
servletContext is springmvc.xml
Our configuration applicationContext.xml Corresponding class
package com.xiaofeifei.security.springmvc.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.stereotype.Controller; @Configuration //amount to applicationContext.xml , after servlet3.0, the configuration can be placed in the class @ComponentScan(basePackages = "com.xiaofeifei.security.springmvc" ,excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)}) //Configure other beans except Controller here, such as database link pool, transaction manager, business bean, etc. Configure springcontext here //controller will configure scan in servletcontext public class ApplicationConfig { }
Our configuration springmvc.xml Corresponding class
package com.xiaofeifei.security.springmvc.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.stereotype.Controller; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.view.InternalResourceViewResolver; @Configuration //This configuration is equivalent to springmvc.xml @EnableWebMvc @ComponentScan(basePackages = "com.xiaofeifei.security.springmvc" ,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)}) //Only packages with Controller annotation are scanned here, because other packages are scanned with ApplicationConfig package public class WebConfig implements WebMvcConfigurer { //Configure view resolver @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/view/"); viewResolver.setSuffix(".jsp"); return viewResolver; } //Direct / direct login.jsp @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("login"); } }
And then we need web.xml , implement ApplicationInitializer or inherit the subclass of this class, which is equivalent to web.xml
package com.xiaofeifei.security.springmvc.init; import com.xiaofeifei.security.springmvc.config.ApplicationConfig; import com.xiaofeifei.security.springmvc.config.WebConfig; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; //A parent interface of the inherited class is WebApplicationInitializer, which is equivalent to web.xml Servlets and listener s configured in public class SpringApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { //The purpose of this method is to load the spring container, that is, load applicationContext.xml @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{ApplicationConfig.class}; //Configure container } //The function is to load servletContext, which is equivalent to loading springmvc.xml @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{WebConfig.class}; // Configure servlet } //The function is to load URL mapping @Override protected String[] getServletMappings() { return new String[]{"/"}; //Configure the access path, here is the root path } }
Create jsp page
Then click Run:
Error will be reported after startup. This lombok is compatible with tomcat7, but does not affect the effect
Define controller
package com.xiaofeifei.security.springmvc.controller; import com.xiaofeifei.security.springmvc.model.AuthenticationRequest; import com.xiaofeifei.security.springmvc.model.UserDto; import com.xiaofeifei.security.springmvc.service.impl.AuthenticationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpSession; @RestController public class LoginController { @Autowired private AuthenticationService authenticationService; @RequestMapping(value = "/login", produces = "text/plain;charset=utf-8") //The role of text/plain;charset=utf-8 is that high-speed browsers return text types public String login(AuthenticationRequest authenticationRequest, HttpSession session) { UserDto userDto = authenticationService.authentication(authenticationRequest); session.setAttribute(UserDto.SESSION_USER_KEY, userDto); return userDto.getUsername() + "Login successful"; } @GetMapping(value = "/logout", produces = "text/plain;charset=utf-8") public String logout(HttpSession session) { session.invalidate(); return "Exit successful"; } @GetMapping(value = "r/r1", produces = "text/plain;charset=utf-8") public String r1(HttpSession session) { String fullname = null; Object object = session.getAttribute(UserDto.SESSION_USER_KEY); if (object == null) { fullname = "anonymous"; }else { UserDto userDto = (UserDto) object; fullname = userDto.getFullname(); } return fullname + "Access resources r1"; } @GetMapping(value = "r/r2", produces = "text/plain;charset=utf-8") public String r2(HttpSession session) { String fullname = null; Object object = session.getAttribute(UserDto.SESSION_USER_KEY); if (object == null) { fullname = "anonymous"; }else { UserDto userDto = (UserDto) object; fullname = userDto.getFullname(); } return fullname + "Access resources r1"; } }
Define interceptor
package com.xiaofeifei.security.springmvc.interceptor; import com.xiaofeifei.security.springmvc.model.UserDto; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @Component public class SimpleAuthenticationInterceptor implements HandlerInterceptor { @Override //We need to intercept before calling all controller public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //In this method, verify whether the url requested by the user is within the user's permission range Object object = request.getSession().getAttribute(UserDto.SESSION_USER_KEY); if (object == null) { writeContent(response, "Please log in"); } UserDto userDto = (UserDto) object; String requestURI = request.getRequestURI(); if (userDto.getAuthorities().contains("p1") && requestURI.contains("/r/r1")) //Accessible / r/r1 with p1 permission { return true; } if (userDto.getAuthorities().contains("p2") && requestURI.contains("/r/r2")) // Those with p2 permission can access / r/r2 { return true; } writeContent(response, "No permission, access denied"); return false; } //Response information to client private void writeContent(HttpServletResponse response, String message) throws IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter writer = response.getWriter(); writer.print(message); writer.close(); } }
Define multiple entity classes
package com.xiaofeifei.security.springmvc.model; import lombok.Data; /** * Request authentication parameters: account and password */ @Data //Use the Data annotation of lombok plug-in, and then generate get and set methods when compiling public class AuthenticationRequest { private String username; private String password; }
package com.xiaofeifei.security.springmvc.model; import lombok.AllArgsConstructor; import lombok.Data; import java.util.Set; /** * User information plug-in */ @Data //Use the Data annotation of lombok plug-in, and then generate get and set methods when compiling @AllArgsConstructor //The function is to take all member variables as parameters of a constructor public class UserDto { public static final String SESSION_USER_KEY = "_user"; //User identity information private String id; private String username; private String password; private String fullname; private String mobile; /** * User rights */ private Set<String> authorities; }
The following is based on security:
The principle of spring security
The accessdecisionmanager class has three implementation classes with different voting rules
Using spring security to solve 403 problems
Among them, the way of stateless is to use token instead of session for authentication and authorization
Exit of spring security
Based on method interception, we usually intercept the controller, because the controller is a user-oriented interface
Distributed system:
The process is as follows: first, the client applies for authorization from the resource owner, gets the authorization (authorization code), then takes the authorization code to access the authentication service to apply for a token, the authentication service judges that the authorization code is correct, then returns the token, and then the client takes the token to access the user information,