Authentication + Authorization Code Implementation
Spring Security is a security framework based on Spring AOP and Servlet filters.It provides a comprehensive security solution while handling authentication and authorization at the Web request and method call levels.
Previously, I blogged about the theory of authentication and authorization. Understanding Rights Management
1. SpringSceurity Workflow
Look for a picture on the Internet and find it very good and easy to understand.Otherwise, the source flowchart is difficult to understand.
Picture address: address You can zoom in and see more clearly on a single machine
To understand this diagram, it is recommended that you look at this blog, because this diagram requires custom M.. classes, which are explained in the article, so you can better understand the point.
2. Authentication + Authorization Code
Only a few core codes are shown here, with the full code on github.
1. UserDetails interface
User interface in Security, which we customize the user class to implement to inject the current user's name, password, and role into security.It also contains other information, such as whether the current user is out of date.
Whether the account is locked, etc.
Define your own User to implement this interface
public class User implements UserDetails { private String username; private String password; private List<Role> roles; /** * Get User Name */ @Override public String getUsername() { return username; } /** * Get Password */ @Override public String getPassword() { return password; } /** * User's permission set, ROLE_needs to be added by defaultprefix */ @Override @JsonIgnore public List<GrantedAuthority> getAuthorities() { List<GrantedAuthority> authorities = new ArrayList<>(); for (Role role : roles) { authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName())); } return authorities; } /** * Is Account Expired */ @Override @JsonIgnore public boolean isAccountNonExpired() { return true; } /** * Is Account Locked */ @Override @JsonIgnore public boolean isAccountNonLocked() { return true; } /** * Does the voucher expire */ @Override @JsonIgnore public boolean isCredentialsNonExpired() { return true; } /** * Is User Available */ @Override public boolean isEnabled() { return true; } }
2,UserDetailsService
User Service in Security. Custom user service classes need to implement this interface.There is only one way to implement this interface, which is to get user information by user name.Here is also the interactive acquisition with the database
A place for user authentication and authorization information.
@Service @Slf4j public class UserService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { //TODO should normally query the database for user and user permissions // User user = userMapper.loadUserByUsername(userName); // List<Role> roles = rolesMapper.getRolesByUid(user.getId()); // user.setRoles(roles); log.info("Logon username: {}", userName); //Password password queried by user name must be encrypted Here clear text password is 123456 String password = "e10adc3949ba59abbe56e057f20f883e"; //User Corresponding Permissions List<Role> roles = Lists.newArrayList(new Role(1L, "Teacher"), new Role(2L, "Student")); User user = new User(userName, password, roles); return user; } }
Note that the clear text password here is 123456, which means the user can enter this to complete the authentication.If authorized, the current user has two roles as a teacher and a student.This will be used in the following tests.
3,WebSecurityConfigurerAdapter
It is the Java configuration class for Spring Security.Create class SecurityConfiguration inherits WebSecurityConfigurerAdapter for all security-related matters in our application(
All url s, validate username passwords, form redirection, etc.) are controlled.
@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { /** * 1,Configuring authentication information, AuthenticationManagerBuilder is the class that builds AuthenticationManager. We only need to configure user information to this class. * The corresponding Authentication Manager can be generated, which is mentioned as the manager of user identity and the entry point for authentication, so we need to configure this configuration to provide real user identity for security. */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { } /** * 2,Configure Security's authentication policy, with each module configuration ending with and.This is also the most complex */ @Override protected void configure(HttpSecurity http) throws Exception { } /** * 3,This configuration method is used to configure how static resources are handled, using Ant matching rules.Is an interface that can be accessed directly without authentication */ @Override public void configure(WebSecurity web) throws Exception { } }
Complete example
@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; /** * Password verifier */ @Autowired private PassWordEncorder passWordEncorder; /** * Success Processor */ @Autowired private AuthenctiationSuccessHandler authenctiationSuccessHandler; /** * Failure Processor */ @Autowired private AuthenctiationFailHandler authenctiationFailHandler; /** * Injecting user information into Security */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService).passwordEncoder(passWordEncorder); } /** * Configuration Rules */ @Override protected void configure(HttpSecurity http) throws Exception { //Turn on login configuration http.authorizeRequests() // Accessible after login .antMatchers("/no-authorize").authenticated() // Principal role privileges are required after landing .antMatchers("/need-authorize").hasRole("Principal") // The other paths are accessible after login .anyRequest().authenticated() .and().formLogin() // Defines a login page, which is automatically jumped to when you access an interface that requires login before it can be accessed .loginPage("/login_page") //Processors Logged on Successfully .successHandler(authenctiationSuccessHandler) //Processors with failed login .failureHandler(authenctiationFailHandler) // Logon Processing Interface .loginProcessingUrl("/login") // Define the key of the user name at login, defaulting to username .usernameParameter("username") //Define the key of the user's password at login, defaulting to password .passwordParameter("password").permitAll() .and().logout() ////All forms login-related interface systems pass directly through .permitAll() .and().csrf().disable().exceptionHandling().accessDeniedHandler(getAccessDeniedHandler()); } /** * No authentication is required for paths under/static/ */ @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/no-login"); } /** * User Unauthenticated Exception Interception */ @Bean AccessDeniedHandler getAccessDeniedHandler() { return new AuthenticationAccessDeniedHandler(); } }
Notice that there are three paths configured for testing.
1. /no-login interface can be accessed directly without authentication 2. /no-authorize requires authentication but does not require authorization to access 3. /need-authorize first requires authentication. Pass also requires authorization where the principal's role is required to access the interface, but we test that users only have teachers and students and therefore do not have access to the interface
This interface is tested separately.
3. Testing
1. Interface Provision
@RestController public class TestController { /** * 1,Access without login */ @RequestMapping(value = "/no-login") public ServiceResponse noLogin() { return ServiceResponse.success("Welcome to an interface that does not require a login"); } /** * 2,Log on only, no authentication interface allowed */ @RequestMapping(value = "/no-authorize") public ServiceResponse needAuthorize(){ return ServiceResponse.success("Logged on without authorization"); } /** * 3,Logon+Related Authentication Interface */ @RequestMapping(value = "/need-authorize") public ServiceResponse noAuthorize() { return ServiceResponse.success("Land+Authorization succeeded"); } /** * @Description: If you automatically jump to this page, indicating that the user is not logged in, return to the appropriate prompt */ @RequestMapping("/login_page") public ServiceResponse loginPage() { return ServiceResponse.failure("001", "Not logged in yet, please log in!"); } }
2. Unlogged access to no-login and no-authorize interfaces
no-login interface
Apparently no logon request for this interface succeeded!
no-authorize interface
No login access failure, configuring above to jump to login_if user is not authenticatedPage interface, so this returns'Not yet logged in, please log in!'
3. Access the no-authorize and need-authorize interfaces after login
Log on first
Request parameters for logon path / login include username and password based on the configuration above
Note that a post request is required here.
no-authorize interface
Log in and you'll be able to access it.
need-authorize interface
Although the login was successful, the access failed because the interface required a principal role, which was previously only configured for the user as a teacher and a student.
Reference resources
1,Security Framework in SpringSide 3
2,Overview of how Spring Security works
3,Spring Boot Security Details Very complimentary
When someone scolds me for being fat, I get angry because I admit I am fat in my heart.I get funny when people say I'm short because I know I can't be short.That's why we get angry at other people's attacks. Those who attack my shield are the spears within me (17)