Specific case of springboot security, implementation of security framework, permission control, aop entry
Introduction to springboot security
Security official Preface
Security is an ever-changing goal, and it is important to pursue a comprehensive and system wide approach. We encourage you to adopt additional layers of security in each area, and we can ensure that you can use such layers of security as much as possible. The more "strict" the security of each layer, the more robust and secure your application will be. At the bottom, in order to reduce man in the middle attacks, you need to deal with issues such as transmission security and system identification. Next, you will usually use a firewall, perhaps through vpn or IP security to ensure that only authorized systems can try to connect. In a corporate environment, you can deploy DMZ to separate public facing servers from back-end database and application servers. Your operating system will also play a key role in addressing issues such as running processes as an unprivileged user and maximizing file system security. The operating system usually also configures its own firewall. Hopefully, somewhere, you can try to prevent distributed denial of service attacks and brute force cracking against the system. Intrusion prevention system security protocol is also particularly useful for monitoring and responding to attacks. Such a system can take protective measures, such as blocking illegal TCP/IP addresses in real time. Moving to a higher tier, your Java virtual machine is expected to be configured to minimize granting permissions to different Java types, and then your application will add its own problem domain specific security configuration. Spring Security makes the latter area -- Application Security -- easier.
There are many reasons why people use Spring Security, but most people start using this project after discovering the security features of Java EE Servlet specification or EJB specification. These features lack the depth required by typical enterprise application scenarios. Although these standards are mentioned, it is important to recognize that they are not portable at the WAR or EAR level. Therefore, if the server environment is switched, it usually requires a lot of work to reconfigure the security of the application in the new target environment. Using Spring Security overcomes these problems and brings you many other useful and customizable security features.
As you may know, the two main aspects of application security are "authentication" and "authorization" (or "access control"). These are the two main goals of Spring Security. "Authentication" is the process of establishing a principal, which is the person they claim ("principal" usually refers to a user, device or other system that can perform an operation in your application). "Authorization" refers to the process of determining whether a principal is allowed to perform operations in an application. In order to reach the point where authorization decisions need to be made, the authentication process has determined the identity of the subject. These concepts are common and are not unique to Spring Security at all.
(I like it very much when I read it myself. I'll add it at the beginning of this article.)
The article is in security 5.0.5 See in the release version document.
https://docs.spring.io/spring-security/site/docs/5.0.5.RELEASE/reference/htmlsingle/
Article introduction
This article is about the Spring Boot integrated spring security framework. The content does not involve too much explanation of specific principles, but only a brief overview.
Suitable for beginners, the status is probably: I don't know much about this, but I need to use spring boot security in the project for the time being.
In the case, there are specific database role table, permission table and resource table, which can be cut into existing projects.
And it's a way to add annotations.
Process, principle, etc. I should also write drops. Believe me... I'm still very curious about this process and principle.
Of course, after reading it, I'm curious. Go to Debug right away, Ollie!!!
There is a line of code in the project that uses the Optional in jdk 8. I wrote an article to explain it before
This is just a practical one. You can have a look.
https://blog.csdn.net/weixin_45821811/article/details/115656637
Database and table
I have finished writing the article of table before. as follows
https://blog.csdn.net/weixin_45821811/article/details/115737401
step
1. Create a spring boot project
Engineering structure drawing
2. Import dependency
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> </dependencies>
3. yaml profile
server: port: 8787 spring: datasource: #Own database name own database password url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useSSL=false&characterEncoding=utf8&serverTimezone=GMT password: 123456 username: root
4,config
-
WebConfig
@Configuration // Equivalent to spring MVC file public class WebConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("redirect:/login"); } }
-
WebSecurityConfig security configuration
@Configuration @EnableWebSecurity // Turn on WebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) // This open permission annotation public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(). //Shielded csrf authorizeRequests() // .antMatchers("/r/r1").hasAnyAuthority("p1") / / this method does not enable permission annotation and does not add permission annotation // .antMatchers("/r/r2").hasAnyAuthority("p2") // .antMatchers("/r/r3").hasAnyAuthority("p1","p2") .antMatchers("/r/**").authenticated() .anyRequest().permitAll() .and() .formLogin() .permitAll() .and() .logout() .logoutUrl("/logout") // Exit url .logoutSuccessUrl("/logout-success"); // After the user-defined login configuration is successful, turn to this url } }
5. pojo layer
-
MyUser user
@Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true)// Chain type public class MyUser { private String id; private String username; private String password; private String fullname; private String mobile; }
-
PermissionDto resource permissions
@Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true)// Chain type public class PermissionDto { private String id; private String code; private String description; private String url; }
6. Dao layer
@Mapper public interface MyUserDao { @Select("select * from user_db where username=#{username}") Optional<MyUser> getUserByName(String username); // Here is a multi table associated query. The structure of the permission table owned by the current role is described in another article @Select("SELECT * FROM t_permission WHERE id IN( SELECT permission_id FROM t_role_permission WHERE role_id IN(SELECT role_id FROM t_user_role WHERE user_id = #{userId} ))") List<PermissionDto> findPermissionsByUserId(String userId); }
7,Service
@Configuration public class SpringDataMyUserDetailsService implements UserDetailsService { @Autowired MyUserDao userDao; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { Optional<MyUser> user = userDao.getUserByName(username); if (user.isPresent()) {// This is a new feature of jdk8, which is described in my article MyUser myUser = user.get(); // Take out operation List<PermissionDto> list = userDao.findPermissionsByUserId(myUser.getId()); System.out.println("list==>" + list.toString()); //List = = > [permissiondto (id = 1, code = P1, description = test resource 1, url=/r/r1)] List<String> permissions = new ArrayList<>(); list.forEach(p -> permissions.add(p.getCode())); System.out.println("permissions===>" + permissions.toString()); //permissions===>[p1] // The reason why it is converted to an array here is that when building UserDetails //. authorities(perarray) where permissions are added, an array can be added, which is more convenient for us to customize //Parameter: permission – the permission of this user (i.e. ROLE_USER, ROLE_ADMIN, etc.). Cannot be null or contain null values // public UserBuilder authorities(String... authorities) { // return authorities(AuthorityUtils.createAuthorityList(authorities)); // } String[] perarray = new String[permissions.size()]; permissions.toArray(perarray); //Create userDetails UserDetails userDetails = User.withUsername(myUser.getUsername()).password( BCrypt.hashpw(myUser.getPassword(), BCrypt.gensalt()) ).authorities(perarray).build(); return userDetails; } return null; } }
8. Controller layer
@RestController public class LoginController { //You all know the back-end return type. I write the text here. json is application/json and the request format. I mostly copy it, not the restful style // You can modify it by yourself @RequestMapping(value = "/login-success", produces = "text/plain;charset=utf-8") public String loginSuccess(){ return getUsername()+"Login successful"; } @RequestMapping(value = "/logout-success", produces = "text/plain;charset=utf-8") public String logout(){ return "Exit successful"; } @RequestMapping(value = "/r/r1", produces = "text/plain;charset=utf-8") // @PreAuthorize("isAnonymous()") / / anonymous access @PreAuthorize("hasAuthority('p1')" ) public String r1(){ return getUsername()+"Resource 1"; } @RequestMapping(value = "/r/r2", produces = "text/plain;charset=utf-8") @PreAuthorize(" hasAuthority('p2')" ) public String r2(){ return getUsername()+"Resource 2"; } @RequestMapping(value = "/r/r3", produces = "text/plain;charset=utf-8") @PreAuthorize("hasAuthority('p1') or hasAuthority('p2')" ) public String r3(){ return getUsername()+"Resource 3"; } // This is that you can access as long as you pass the authentication, and you don't need the permission of the subject @RequestMapping(value = "/r/r4", produces = "text/plain;charset=utf-8") public String r4(){ return getUsername()+"Resources 4"; } private String getUsername(){ String username=null; //Current user identity Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Object principal = authentication.getPrincipal(); if (principal==null){ username="anonymous"; } if(principal instanceof UserDetails){ UserDetails userDetails= (UserDetails)principal; username = userDetails.getUsername(); }else{ username= principal.toString(); } return username; } }
9. Startup class
@SpringBootApplication @MapperScan("com.wyh.dao") public class SecuritySpringbootApplication { public static void main(String[] args) { SpringApplication.run(SecuritySpringbootApplication.class, args); } }
Next is the test. And my self talk
test
authentication
Authentication successful
Authentication error
sign out
to grant authorization
admin has p1 permission and can access / r/r1 resources
admin does not have p2 permission and cannot access the / r/r2 resource
/r/r3 can be accessed with p1 permission or p2 permission, but it cannot be accessed without it
/r/r4 can be accessed as long as the identity authentication is passed
think aloud
Record your life every day and get used to writing here and there every day.
At first, I wanted to make it convenient for myself to read, but when I wrote, I began to want people to pay attention to it.
It's better than casually writing the current words at the beginning.
I suddenly want to record what I know. Maybe I want people to know.
There are so many things to learn.
Keep going.