SecurityConfig
package com.jay.SpringBootStudy8.config; import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 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; import org.springframework.security.config.http.SessionCreationPolicy; 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.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)//方法授权 public class SecurityConfig extends WebSecurityConfigurerAdapter { //用数据库查询的话,就不需要在这里模拟用户了 // @Bean // public UserDetailsService userDetailsService(){ // InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); // manager.createUser(User.withUsername("user2").password("123456").authorities("add","delete","update").roles("vip1").build()); // manager.createUser(User.withUsername("user3").password("123456").authorities("add","delete","update").roles("vip2").build()); // return manager; // } //密码编码器 @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } //认证 // @Override // protected void configure(AuthenticationManagerBuilder auth) throws Exception { // super.configure(auth); //BCryptPasswordEncoder 加密方式,用户名admin、密码123456,可以and()连接多个 // auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) // .withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1") // .and() // .withUser("user1").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2") // ; // } //授权 @Override protected void configure(HttpSecurity http) throws Exception { //Security 创建 Session,使用Session保持会话,如果使用 jwt Token,则可以设置成STATELESS,不生成也不是用Session http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS); //使用方法授权,不需要下面的web授权配置 //功能页只有具有权限的人才能访问 // http.authorizeRequests() // .antMatchers("/level1").hasRole("vip1") // .antMatchers("/level2").hasRole("vip2") // .antMatchers("/level3").authenticated() // .anyRequest().permitAll(); //禁用csrf跨站 // <!--加上后不用禁用csrf--> // <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> // http.csrf().disable(); //开启登录,定制登录页,自定义请求参数名 和 登录请求地址。 //如果不自定义登录请求地址,那登录form的action需要是loginPage指定的地址 /userLogin http.formLogin().loginPage("/userLogin") .usernameParameter("name") .passwordParameter("pwd") .loginProcessingUrl("/userLogin") .successForwardUrl("/level1") ; //记住我,自定义请求参数 http.rememberMe().rememberMeParameter("remember"); //注销、删除cookie、清除session、跳转登录页 http.logout().deleteCookies("remove").invalidateHttpSession(true).logoutSuccessUrl("/userLogin"); } }
SpringDataUserDetailsService
package com.jay.SpringBootStudy8.config; import com.jay.SpringBootStudy8.pojo.Permission; import com.jay.SpringBootStudy8.pojo.Role; import com.jay.SpringBootStudy8.pojo.SysUser; import com.jay.SpringBootStudy8.service.PermissionService; import com.jay.SpringBootStudy8.service.RoleService; import com.jay.SpringBootStudy8.service.SysUserService; import org.springframework.beans.factory.annotation.Autowired; 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.Service; import java.util.List; import java.util.stream.Collectors; @Service public class SpringDataUserDetailsService implements UserDetailsService { @Autowired private SysUserService sysUserService; @Autowired private RoleService roleService; @Autowired private PermissionService permissionService; //根据账户查询用户 @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { System.out.println("userName:" + s); //连接数据库 123456 md5密码 efd9d1b8bfb00e8e3647990f7d74d1d8,BCrypt密码 $2a$10$bobysVYApzaZF2RhNcIQp.qum8V1e9jg5jkqStlRKkfXkB0y4P5AC SysUser user = sysUserService.getModelByUserName(s); if (user != null) { List<Role> roles = roleService.getAllByUserId(user.getId()); List<String> roleNames = roles.stream().map(Role::getName).collect(Collectors.toList()); List<Integer> roleIds = roles.stream().map(Role::getId).collect(Collectors.toList()); List<Permission> permissions = permissionService.getAllByRoleIds(roleIds); List<String> permissionCodes = permissions.stream().map(Permission::getCode).collect(Collectors.toList()); User.UserBuilder builder = User.withUsername(user.getUserName()).password(user.getPwd()); builder.authorities(permissionCodes.toArray(new String[0])); // builder.roles(roleNames.toArray(new String[0]));//roles会替换authorities的赋值 UserDetails userDetails = builder.build(); return userDetails; } return null; } }
Controller》Action
@RequestMapping("/level1") @PreAuthorize("hasAuthority('users:mgr')")//方法授权,方法执行前校验,建议使用 public String level1(Model model) { //得到当前认证通过的用户身份,用户的信息都在这里存着 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();//用户权限 Object credentials = authentication.getCredentials();//用户凭证 Object details = authentication.getDetails();//用户详细信息 Object principal = authentication.getPrincipal();//用户身份 UserDetails userDetails = (UserDetails) principal; String userName = userDetails.getUsername(); model.addAttribute("userName",userName); return "views/level1/1"; }
前端:
<!DOCTYPE html> <html lang="en_US" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>login</title> </head> <body> <h1>login</h1> <a th:href="@{/logout}">注销</a> <a th:href="@{/userLogin}">login</a> <p th:text="${msg}" style="color: red;"></p> <form method="post" th:action="@{/userLogin}"> <!--加上后不用禁用csrf--> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> name:<input type="text" name="name"/> <br/> pwd:<input type="password" name="pwd"/> <br/> <input type="checkbox" name="remember"/>Remember Me <br/> <button type="submit">submit</button> </form> </body> </html>
视频:https://www.bilibili.com/video/BV1VE411h7aL?p=25