SpringSecurity
Related concepts
- Principal [user or device using the system or user logging in remotely from other systems, etc. in short, whoever uses the system is the principal.]
- Authentication [the authority management system confirms the identity of an entity and allows the entity to enter the system. In short, it means that the "entity" proves who it is. In general, it means the previous login operation]
- Authorization [authorize the "power" of the operating system to the "principal", so that the principal has the ability of specific functions in the operating system. Therefore, in short, authorization is to assign permissions to users]
Mainstream framework of rights management
1,SpringSecurity
Part of the spring technology stack.
characteristic:
- Seamless integration with spring
- Comprehensive authority control
- Designed specifically for Web development
- The old version cannot be used without the Web environment.
- The new version extracts the whole framework hierarchically, which is divided into core module and Web module. The introduction of core modules alone can break away from the Web environment
- heavyweight
2,Shiro
Apache's lightweight permission control framework.
characteristic:
- Lightweight. Shiro advocates the idea of making complex things simple. Better performance for Internet applications with higher performance requirements.
- generality.
- Benefits: it is not limited to the Web environment and can be used without the Web environment.
- Defect: in the Web environment, some specific requirements require manual code customization.
Environment construction
1. Create maven project and add spring MVC dependency package
<?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.atguigu.security</groupId> <artifactId>SpringSecurity</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.20.RELEASE</version> </dependency> <!-- introduce Servlet Dependency in container --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <!-- JSP Dependency of page usage --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.1.3-b06</version> <scope>provided</scope> </dependency> </dependencies> </project>
2. Create the springMvc configuration file Spirng MVC xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd"> <!-- Annotation scan --> <context:component-scan base-package="com.atguigu.security"/> <!-- view resolver --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> <mvc:annotation-driven/> <mvc:default-servlet-handler/> </beans>
3. Configure Wen xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <!-- Configure front-end controller --> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <!-- load springmvc configuration file--> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <!-- Load level--> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
4. Add handler and front-end data [omit adding, and you can access it normally after startup]
5. Add spring security dependency package based on spring MVC
<!-- SpringSecurity yes Web Application for permission management --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>4.2.10.RELEASE</version> </dependency> <!-- SpringSecurity to configure --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.2.10.RELEASE</version> </dependency> <!-- SpringSecurity Tag library --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>4.2.10.RELEASE</version> </dependency>
6. On the web XML add a Filter with spring security control permission [cannot be accessed normally after adding]
Note:
The name of < Filter name > springSecurityFilterChain < / Filter name > must be springSecurityFilterChain. Because the springSecurityFilterChain corresponds to more than twenty filters that actually perform permission control in the IOC container, only by calling this name can they be loaded into these filters.
Why use Filter instead of Interceptor?
The filtering range of Filter is larger than that of Interceptor. In addition to filtering requests, Filter can protect pages, pictures, files, etc. through wildcards, while Interceptor can only Filter requests.
<!-- SpringSecurity Control authority Filter --> <filter> <!-- It must be called, or it won't be recognized springSecurityFilterChain--> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
To this effect:
All requests are blocked by spring security and require login to access
Static resources are also blocked and require login
Login failed with error prompt
Project address handler and front-end data fetching
experiment:
Experiment 1: release home page and static resources
1. Add configuration class
package com.atguigu.security.config; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; /** * WebAppSecurityConfig * Configuration class * * @author Zhao Changchun * @version [Version number, 2021 / 1 / 12 [17:16] * @see [Related classes / methods] * @since [Product / module version] */ @Configuration //Replace xml configuration file @EnableWebSecurity // Indicates that web security is enabled public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter { } }
2. Override the configure method in the parent WebSecurityConfigurerAdapter
Parent class configure method [the default rule is that any request for access must be logged in]
protected void configure(HttpSecurity http) throws Exception { this.logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity)."); ((HttpSecurity)((HttpSecurity)((AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated().and()).formLogin().and()).httpBasic(); }
Rewritten configure method [release homepage and static resources]
/*** * Override configure * Modify default rule * The default rule is that any request for access must be logged in * @param security * @throws Exception */ @Override protected void configure(HttpSecurity security) throws Exception { //super.configure(security); Commenting out cancels the default rule in the parent class method security //Authorize requests .authorizeRequests() //For / index JSP for authorization .antMatchers("/index.jsp") //Unconditional access .permitAll() //Authorize for / layui / * * .antMatchers("/layui/**") //Unconditional access .permitAll() .and() //Authorize requests .authorizeRequests() // Arbitrary request .anyRequest() // You need to log in before you can access it normally .authenticated(); }
==At this time, the effect: = = login is successful, and the unauthenticated request will jump to the HTTP Status 403 - Access Denied page
Experiment 2: jump to the login page without authentication
Continue adding in configure
/*** * Override configure * Modify default rule * The default rule is that any request for access must be logged in * @param security * @throws Exception */ @Override protected void configure(HttpSecurity security) throws Exception { //super.configure(security); Commenting out cancels the default rule in the parent class method security //Authorize requests .authorizeRequests() //For / index JSP for authorization .antMatchers("/index.jsp") //Unconditional access .permitAll() //Authorize for / layui / * * .antMatchers("/layui/**") //Unconditional access .permitAll() .and() //Authorize requests .authorizeRequests() // Arbitrary request .anyRequest() // You need to log in before you can access it normally .authenticated() .and() // Set the unauthorized request to jump to the login page and default to the form login page .formLogin() //Jump to login page .loginPage("/index.jsp") // Specify the address to submit the login form. If the loginprocessing URL () method specifies the login address, the default value set in the loginPage() method will be overwritten .failureForwardUrl("/to/login"); }
==Effect = =: the unauthorized access request will jump to the login page
Experiment 3: set the account and password to log in to the system
1. Add information in the configure method of the configuration class WebAppSecurityConfig
/*** * Override configure * Modify default rule * The default rule is that any request for access must be logged in * @param security * @throws Exception */ @Override protected void configure(HttpSecurity security) throws Exception { //super.configure(security); Commenting out cancels the default rule in the parent class method security //Authorize requests .authorizeRequests() //For / index JSP for authorization .antMatchers("/index.jsp") //Unconditional access .permitAll() //Authorize for / layui / * * .antMatchers("/layui/**") //Unconditional access .permitAll() .and() //Authorize requests .authorizeRequests() // Arbitrary request .anyRequest() // You need to log in before you can access it normally .authenticated() .and() // Set the unauthorized request to jump to the login page and default to the form login page .formLogin() //Jump to login page .loginPage("/index.jsp") // Specify the address to submit the login form. If the loginprocessing URL () method specifies the login address, the default value set in the loginPage() method will be overwritten .loginProcessingUrl("/do/login.html") //The request parameter name of customized login account is not set to username by default .usernameParameter("loginAcct") //The request parameter name of customized login password is not set to password by default .passwordParameter("userPswd") //Set the default login address to jump after successful login .defaultSuccessUrl("/main.html"); }
2. Override another method of the parent class, configure
Why set the role [. roles("ADMIN")] or authority ("save", "Edit")? Spring security submits a complete "principal".
Simply put, when a user logs in, spring security will verify whether the user has a role or permission
If it is not set, an error will be reported: = = Cannot pass a null GrantedAuthority collection==
/*** * Override another configure method of the parent class * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // super.configure(auth); Disable default rule //Compare in memory auth.inMemoryAuthentication() //Set user name and password .withUser("tom").password("123123") // Set role .roles("ADMIN") .and() //Set user name and password .withUser("jerry").password("123123") //Set permissions .authorities("SAVE", "EDIT"); }
3. Front end add
Not carried when sending login request_ csrf value, the following error is returned: = = HTTP Status 403 - Could not verify the provided CSRF token because your session was not found==
<p>${SPRING_SECURITY_LAST_EXCEPTION.message}</p> <form action="${pageContext.request.contextPath }/do/login.html"method="post"> <input type="hidden"name="${_csrf.parameterName}"value="${_csrf.token}"/> ...... </form>
Implementation effect: after logging in, specific resources can be accessed.
Experiment 4: exit
The first way: csrf is not required
1. Disable csrf
/*** * Override configure * Modify default rule * The default rule is that any request for access must be logged in * @param security * @throws Exception */ @Override protected void configure(HttpSecurity security) throws Exception { //super.configure(security); Commenting out cancels the default rule in the parent class method security //Authorize requests .authorizeRequests() //For / index JSP for authorization .antMatchers("/index.jsp") //Unconditional access .permitAll() //Authorize for / layui / * * .antMatchers("/layui/**") //Unconditional access .permitAll() .and() // //Authorize requests .authorizeRequests() // Arbitrary request .anyRequest() // You need to log in before you can access it normally .authenticated() .and() // Set the unauthorized request to jump to the login page and default to the form login page .formLogin() //Jump to login page .loginPage("/index.jsp") // Specify the address to submit the login form. If the loginprocessing URL () method specifies the login address, the default value set in the loginPage() method will be overwritten .loginProcessingUrl("/do/login.html") //The request parameter name of customized login account is not set to username by default .usernameParameter("loginAcct") //The request parameter name of customized login password is not set to password by default .passwordParameter("userPswd") //Set the default login address to jump after successful login .defaultSuccessUrl("/main.html") .and() .csrf() .disable()//Disable csrf function .logout() //Enable login function .logoutUrl("/do/logout.html")//Specify the url address to process the push request .logoutSuccessUrl("/index.jsp"); // Address to go after successful exit }
2. Front end
<a href="/do/logout.html">sign out
The second method: do not disable crsf
1. Enable login function
/*** * Override configure * Modify default rule * The default rule is that any request for access must be logged in * @param security * @throws Exception */ @Override protected void configure(HttpSecurity security) throws Exception { //super.configure(security); Commenting out cancels the default rule in the parent class method security //Authorize requests .authorizeRequests() //For / index JSP for authorization .antMatchers("/index.jsp") //Unconditional access .permitAll() //Authorize for / layui / * * .antMatchers("/layui/**") //Unconditional access .permitAll() .and() // //Authorize requests .authorizeRequests() // Arbitrary request .anyRequest() // You need to log in before you can access it normally .authenticated() .and() // Set the unauthorized request to jump to the login page and default to the form login page .formLogin() //Jump to login page .loginPage("/index.jsp") // Specify the address to submit the login form. If the loginprocessing URL () method specifies the login address, the default value set in the loginPage() method will be overwritten .loginProcessingUrl("/do/login.html") //The request parameter name of customized login account is not set to username by default .usernameParameter("loginAcct") //The request parameter name of customized login password is not set to password by default .passwordParameter("userPswd") //Set the default login address to jump after successful login .defaultSuccessUrl("/main.html") .and() // .csrf() // . disable() / / disable csrf function .logout() //Enable login function .logoutUrl("/do/logout.html")//Specify the url address to process the push request .logoutSuccessUrl("/index.jsp"); // Address to go after successful exit }
Step 2: front end
<form id="logoutForm" action="${pageContext.request.contextPath }/do/logout.html" method="post"> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> </form> <a id="logoutAnchor" href="">sign out</a> <script type="text/javascript"> window.onload = function() { // Bind a stand-alone response function to the dom object of the hyperlink document.getElementById("logoutAnchor").onclick = function() { // Submit a form with crsf parameters document.getElementById("logoutForm").submit(); // Disable hyperlink default behavior return false; }; }; </script>
Experiment 5: access control based on role live permission
1. Modify the two methods of configure
/*** * Override configure * Modify default rule * The default rule is that any request for access must be logged in * @param security * @throws Exception */ @Override protected void configure(HttpSecurity security) throws Exception { //super.configure(security); Commenting out cancels the default rule in the parent class method security //Authorize requests .authorizeRequests() //For / index JSP for authorization .antMatchers("/index.jsp") //Unconditional access .permitAll() //Authorize for / layui / * * .antMatchers("/layui/**") //Unconditional access .permitAll() //Set the address matching / level1 / * * .antMatchers("/level1/**") // Requires an "Apprentice role" to access .hasRole("apprentice") // //Set the address matching / level2 / * * .antMatchers("/level2/**") // It is required to have "inner door bottom permission" to access .hasAuthority("Inner disciple") .and() // //Authorize requests .authorizeRequests() // Arbitrary request .anyRequest() // You need to log in before you can access it normally .authenticated() .and() // Set the unauthorized request to jump to the login page and default to the form login page .formLogin() //Jump to login page .loginPage("/index.jsp") // Specify the address to submit the login form. If the loginprocessing URL () method specifies the login address, the default value set in the loginPage() method will be overwritten .loginProcessingUrl("/do/login.html") //The request parameter name of customized login account is not set to username by default .usernameParameter("loginAcct") //The request parameter name of customized login password is not set to password by default .passwordParameter("userPswd") //Set the default login address to jump after successful login .defaultSuccessUrl("/main.html") .and() // .csrf() // . disable() / / disable csrf function .logout() //Enable login function .logoutUrl("/do/logout.html")//Specify the url address to process the push request .logoutSuccessUrl("/index.jsp"); // Address to go after successful exit }
/*** * Override another configure method of the parent class * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // super.configure(auth); Disable default rule //Compare in memory auth.inMemoryAuthentication() //Set user name and password .withUser("tom").password("123123") // Set role .roles("ADMIN","apprentice") .and() //Set user name and password .withUser("jerry").password("123123") //Set permissions .authorities("SAVE", "EDIT","Inner disciple"); }
Source code analysis:
When adding = = 'role' = = to the user, it will be prefixed automatically_ ROLE .roles("ADMIN", "Apprentice")
public User.UserBuilder roles(String... roles) { List<GrantedAuthority> authorities = new ArrayList(roles.length); String[] var3 = roles; int var4 = roles.length; for(int var5 = 0; var5 < var4; ++var5) { String role = var3[var5]; // If you add a prefix manually, you will be reminded not to add it manually, and it will be added automatically Assert.isTrue(!role.startsWith("ROLE_"), role + " cannot start with ROLE_ (it is automatically added)"); authorities.add(new SimpleGrantedAuthority("ROLE_" + role)); }
There is no prefix when adding = = 'permission' = = authorities("SAVE", "EDIT", "inner disciple");
public User.UserBuilder authorities(String... authorities) { return this.authorities((Collection)AuthorityUtils.createAuthorityList(authorities)); }
Experiment 6:403 custom error page
1. Modify the configure method
It can also be used accessDeniedHandler(new AccessDeniedHandler() {}) extension all handlers that use * * * handler can be customized
/*** * Override configure * Modify default rule * The default rule is that any request for access must be logged in * @param security * @throws Exception */ @Override protected void configure(HttpSecurity security) throws Exception { //super.configure(security); Commenting out cancels the default rule in the parent class method security //Authorize requests .authorizeRequests() //For / index JSP for authorization .antMatchers("/index.jsp") //Unconditional access .permitAll() //Authorize for / layui / * * .antMatchers("/layui/**") //Unconditional access .permitAll() //Set the address matching / level1 / * * .antMatchers("/level1/**") // Requires an "Apprentice role" to access .hasRole("apprentice") // //Set the address matching / level2 / * * .antMatchers("/level2/**") // It is required to have "inner door bottom permission" to access .hasAuthority("Inner disciple") .and() // //Authorize requests .authorizeRequests() // Arbitrary request .anyRequest() // You need to log in before you can access it normally .authenticated() .and() // Set the unauthorized request to jump to the login page and default to the form login page .formLogin() //Jump to login page .loginPage("/index.jsp") // Specify the address to submit the login form. If the loginprocessing URL () method specifies the login address, the default value set in the loginPage() method will be overwritten .loginProcessingUrl("/do/login.html") //The request parameter name of customized login account is not set to username by default .usernameParameter("loginAcct") //The request parameter name of customized login password is not set to password by default .passwordParameter("userPswd") //Set the default login address to jump after successful login .defaultSuccessUrl("/main.html") .and() // .csrf() // . disable() / / disable csrf function .logout() //Enable login function .logoutUrl("/do/logout.html")//Specify the url address to process the push request .logoutSuccessUrl("/index.jsp") // Address to go after successful exit .and() // Specify exception handler .exceptionHandling() // Page to go when access is denied .accessDeniedPage("/to/no/auth/page.html") // Custom handler error prompt .accessDeniedHandler(new AccessDeniedHandler() { public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException { request.setAttribute("message","i 'm sorry! You cannot access the current page!!!!"); request.getRequestDispatcher("/WEB-INF/views/no_auth.jsp").forward(request,response); } }) ; }
Experiment 7: remember me (memory version is not important)
1. The HttpSecurity object calls the rememberMe() method to open.
/*** * Override configure * Modify default rule * The default rule is that any request for access must be logged in * @param security * @throws Exception */ @Override protected void configure(HttpSecurity security) throws Exception { //super.configure(security); Commenting out cancels the default rule in the parent class method security //Authorize requests .authorizeRequests() //For / index JSP for authorization .antMatchers("/index.jsp") //Unconditional access .permitAll() //Authorize for / layui / * * .antMatchers("/layui/**") //Unconditional access .permitAll() //Set the address matching / level1 / * * .antMatchers("/level1/**") // Requires an "Apprentice role" to access .hasRole("apprentice") // //Set the address matching / level2 / * * .antMatchers("/level2/**") // It is required to have "inner door bottom permission" to access .hasAuthority("Inner disciple") .and() // //Authorize requests .authorizeRequests() // Arbitrary request .anyRequest() // You need to log in before you can access it normally .authenticated() .and() // Set the unauthorized request to jump to the login page and default to the form login page .formLogin() //Jump to login page .loginPage("/index.jsp") // Specify the address to submit the login form. If the loginprocessing URL () method specifies the login address, the default value set in the loginPage() method will be overwritten .loginProcessingUrl("/do/login.html") //The request parameter name of customized login account is not set to username by default .usernameParameter("loginAcct") //The request parameter name of customized login password is not set to password by default .passwordParameter("userPswd") //Set the default login address to jump after successful login .defaultSuccessUrl("/main.html") .and() // .csrf() // . disable() / / disable csrf function .logout() //Enable login function .logoutUrl("/do/logout.html")//Specify the url address to process the push request .logoutSuccessUrl("/index.jsp") // Address to go after successful exit .and() // Specify exception handler .exceptionHandling() // Page to go when access is denied .accessDeniedPage("/to/no/auth/page.html") .and() // Open and remember me .rememberMe() ; }
2. Front end
The login form carries a request parameter named remember me. The specific method is to set the name of the checkbox in the login form to remember me
<input type="checkbox" name="remember-me" lay-skin="primary" title="Remember me"> <a href="forget.html" class="layadmin-user-jump-change layadmin-link" style="margin-top: 7px;">Forget the password?</a>
Experiment 8: remember me (database version)
1,pom.xml join database dependency
<!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> <!-- mysql drive --> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>4.3.20.RELEASE</version> </dependency>
2,sprng-mvc.xml add configuration
<!-- Configure data source --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="username" value="root"></property> <property name="password" value="admin"></property> <property name="url" value="jdbc:mysql://localhost:3306/security?useSSL=false"></property> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> </bean> <!-- jdbcTemplate--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean>
3. WebAppSecurityConfig add configuration
① Injection data source @Autowired private DataSource dataSource; ②configure Add configuration JdbcTokenRepositoryImpl tokenRepositoy = new JdbcTokenRepositoryImpl(); tokenRepositoy.setDataSource(dataSource); security.rememberMe().tokenRepository(tokenRepositoy) Specific code /*** * Override configure * Modify default rule * The default rule is that any request for access must be logged in * @param security * @throws Exception */ @Override protected void configure(HttpSecurity security) throws Exception { //super.configure(security); Commenting out cancels the default rule in the parent class method JdbcTokenRepositoryImpl tokenRepositoy = new JdbcTokenRepositoryImpl(); tokenRepositoy.setDataSource(dataSource); security //Authorize requests .authorizeRequests() //For / index JSP for authorization .antMatchers("/index.jsp") //Unconditional access .permitAll() //Authorize for / layui / * * .antMatchers("/layui/**") //Unconditional access .permitAll() //Set the address matching / level1 / * * .antMatchers("/level1/**") // Requires an "Apprentice role" to access .hasRole("apprentice") // //Set the address matching / level2 / * * .antMatchers("/level2/**") // It is required to have "inner door bottom permission" to access .hasAuthority("Inner disciple") .and() // //Authorize requests .authorizeRequests() // Arbitrary request .anyRequest() // You need to log in before you can access it normally .authenticated() .and() // Set the unauthorized request to jump to the login page and default to the form login page .formLogin() //Jump to login page .loginPage("/index.jsp") // Specify the address to submit the login form. If the loginprocessing URL () method specifies the login address, the default value set in the loginPage() method will be overwritten .loginProcessingUrl("/do/login.html") //The request parameter name of customized login account is not set to username by default .usernameParameter("loginAcct") //The request parameter name of customized login password is not set to password by default .passwordParameter("userPswd") //Set the default login address to jump after successful login .defaultSuccessUrl("/main.html") .and() // .csrf() // . disable() / / disable csrf function .logout() //Enable login function .logoutUrl("/do/logout.html")//Specify the url address to process the push request .logoutSuccessUrl("/index.jsp") // Address to go after successful exit .and() // Specify exception handler .exceptionHandling() // Page to go when access is denied .accessDeniedPage("/to/no/auth/page.html") .and() // Open and remember me .rememberMe() .tokenRepository(tokenRepositoy) ; }
4. Add database
DROP DATABASE IFEXISTS `security`; CREATE DATABASE IF NOT EXISTS `security` character set utf8; use `security`; CREATE TABLE if not exists persistent_logins ( username VARCHAR ( 64 ) NOT NULL, series VARCHAR ( 64 ) PRIMARY KEY, token VARCHAR ( 64 ) NOT NULL, last_used TIMESTAMP NOT NULL );
Experiment 9: database login
1. Create database
drop table if exists t_admin; CREATE TABLE if not exists t_admin ( id INT NOT NULL auto_increment, loginacct VARCHAR ( 255 ) NOT NULL, userpswd CHAR ( 32 ) NOT NULL, username VARCHAR ( 255 ) NOT NULL, email VARCHAR ( 255 ) NOT NULL, createtime CHAR ( 19 ), PRIMARY KEY ( id ) );
2. Write UserDetailsService implementation class
package com.atguigu.security.config; import com.atguigu.security.entity.Admin; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; /** * MyUserDetailsService * <Detailed function description > * * @author Zhao Changchun * @version [Version number, 2021 / 1 / 14 17:49] * @see [Related classes / methods] * @since [Product / module version] */ @Component public class MyUserDetailsService implements UserDetailsService { @Autowired private JdbcTemplate jdbcTemplate; /*** * Query the User object according to the User name submitted by the form, and assemble the role, permission and other information * @param s * @return * @throws UsernameNotFoundException */ public UserDetails loadUserByUsername( // User name for form submission String userName) throws UsernameNotFoundException { // 1. Query admin object from database String sql = "SELECT id,loginAcct,userPswd,userName,email,createtime FROM t_admin WHERE loginacct = ?"; List<Admin> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Admin>(Admin.class), userName); Admin admin = list.get(0); String userPswd = admin.getUserPswd(); // Set object permission information for admin List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); authorities.add(new SimpleGrantedAuthority("UPDATE")); // Encapsulate the admin object and authorities into UserDetails return new User(userName, userPswd, authorities); } }
3. Modify the configure method in the WebAppSecurityConfig class
/*** * Override another configure method of the parent class * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // super.configure(auth); Disable default rule //Compare in memory // auth.inMemoryAuthentication() / / check the account and password in memory // //Set user name and password // .withUser("tom").password("123123") // //Set role // . roles("ADMIN", "Apprentice") // .and() // //Set user name and password // .withUser("jerry").password("123123") // //Set permissions // . authorities("SAVE", "EDIT", "inner disciple"); // Assemble userDetailsService object auth.userDetailsService(userDetailsService); }
Experiment 10: password encryption (MD5)
1. Customize MyUserDetailsService class to implement UserDetailsService
package com.atguigu.security.config; import com.atguigu.security.entity.Admin; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; /** * MyUserDetailsService * <Customize MyUserDetailsService to complete database user login > * * @author Zhao Changchun * @version [Version number, 2021 / 1 / 14 17:49] * @see [Related classes / methods] * @since [Product / module version] */ @Component public class MyUserDetailsService implements UserDetailsService { @Autowired private JdbcTemplate jdbcTemplate; /*** * Query the User object according to the User name submitted by the form, and assemble the role, permission and other information * @param s * @return * @throws UsernameNotFoundException */ public UserDetails loadUserByUsername( // User name for form submission String userName) throws UsernameNotFoundException { // 1. Query admin object from database String sql = "SELECT id,loginAcct,userPswd,userName,email,createtime FROM t_admin WHERE loginacct = ?"; List<Admin> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Admin>(Admin.class), userName); Admin admin = list.get(0); String userPswd = admin.getUserPswd(); // Set object permission information for admin List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); authorities.add(new SimpleGrantedAuthority("ROLE_apprentice")); authorities.add(new SimpleGrantedAuthority("UPDATE")); // Encapsulate the admin object and authorities into UserDetails return new User(userName, userPswd, authorities); } }
2. Add configuration passwordEncoder() to configure of WebAppSecurityConfig configuration class
@Autowired private MyPasswordEncoder passwordEncoder; /*** * Override another configure method of the parent class * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // Assemble userDetailsService object auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder); }
Disadvantages: the encrypted ciphertext remains unchanged and is easy to crack
Experiment 11: password encryption (with salt value)
1. Inject BCryptPasswordEncoder into the configuration class
/*** * Use encryption with salt value * @return */ // The default singleton will not be created repeatedly @Bean public BCryptPasswordEncoder getBCryptPasswordEncoder(){ return new BCryptPasswordEncoder(); }
2. Modify configure
/*** * Override another configure method of the parent class * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // Assemble userDetailsService object auth.userDetailsService(userDetailsService).passwordEncoder(getBCryptPasswordEncoder());