Spring?Security權(quán)限管理小結(jié)
1 Spring Security配置用戶名和密碼
方式一:在application.properties文件中配置
# 配置security用戶名密碼 spring.security.user.password=LIFEILIN spring.security.user.name=LIFEILIN spring.security.user.roles=admin
方式二:代碼配置
@Configuration
public class securityConfig extends WebSecurityConfigurerAdapter {
//暫且密碼不加密
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("LIFEILIN").password("LIFEILIN").roles("admin") //第一個(gè)
.and()
.withUser("123").password("123").roles("user"); //第二個(gè)
}
}2 HttpSecurity的配置
//配置HttpSecurity攔截規(guī)則
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //開啟配置
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasAnyRole("admin","user")
.anyRequest().authenticated() //其他請(qǐng)求登錄后即可訪問
.and()
.formLogin()
.loginProcessingUrl("/doLogin")
.permitAll() //跟登錄相關(guān)接口直接訪問
.and()
.csrf().disable();
}3 登錄/注銷表單詳細(xì)配置
//配置HttpSecurity攔截規(guī)則
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //開啟配置
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasAnyRole("admin", "user")
.anyRequest().authenticated() //其他請(qǐng)求登錄后即可訪問
.and()
.formLogin()
.loginProcessingUrl("/doLogin")
// .loginPage("login") //登錄頁面
//自定義用戶名密碼
.usernameParameter("uname")
.passwordParameter("passwd")
//登錄成功的處理器(前后端分離)
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException { //authentication為登錄成功對(duì)象
//登錄成功,返回json
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", authentication.getPrincipal()); //登錄成功對(duì)象
out.write(new ObjectMapper().writeValueAsString(map)); //將map轉(zhuǎn)為json寫出去
out.flush();
out.close();
}
})
//登錄失敗的處理器(前后端分離)
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status", 401);
if (e instanceof LockedException){ //賬號(hào)鎖定
map.put("msg","賬號(hào)被鎖定,登錄失敗");
}else if (e instanceof BadCredentialsException){
map.put("msg","用戶名和密碼輸入錯(cuò)誤,登錄失敗");
}else if (e instanceof DisabledException){
map.put("msg","賬號(hào)被禁用,登錄失敗");
}else if (e instanceof AccountExpiredException){
map.put("msg","賬戶過期,登錄失敗");
}else if (e instanceof CredentialsExpiredException){
map.put("msg","密碼過期,登錄失敗");
}else {
map.put("msg","登錄失敗");
}
out.write(new ObjectMapper().writeValueAsString(map)); //將map轉(zhuǎn)為json寫出去
out.flush();
out.close();
}
})
.permitAll() //跟登錄相關(guān)接口直接訪問
.and()
//注銷登錄
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", "注銷登錄成功"); //注銷登錄成功
out.write(new ObjectMapper().writeValueAsString(map)); //將map轉(zhuǎn)為json寫出去
out.flush();
out.close();
}
})
.and()
.csrf().disable();
}


4 多個(gè)HttpSecurity的配置
配置類不需要繼承WebSecurityConfigurerAdapter方法,直接注入:configure方法
@Configuration
public class MultiHttpSecurityConfig {
//暫且密碼不加密
@Bean
PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
//配置用戶名和密碼
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("LIFEILIN").password("LIFEILIN").roles("admin") //第一個(gè)
.and()
.withUser("123").password("123").roles("user"); //第二個(gè)
}
@Configuration
@Order(1)
public static class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/admin/**").authorizeRequests().anyRequest().hasRole("admin"); //admin角色訪問
}
}
@Configuration
public static class OtherSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/doLogin")
.permitAll()
.and()
.csrf().disable();
}
}
}
5 密碼加密
相同的明文可加密成不同的密文,不用維護(hù)原字段。
@Test
void contextLoads() {
for (int i=0;i<10;i++){
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
System.out.println(encoder.encode("123"));
}
}
明文【123】加密后:
$2a 10 10 10SS.YDon5lzqkIFdW8DQYzOTJBvQwkdXHWcHlIfF1fa/wPjJtru5aO
$2a 10 10 10vJsPq4GBtHKmmBQaKTriTO90sFurCEDavZANqCoqGu4gAzXxGLbTC
$2a 10 10 10gZ4H3/tBRpz2lPX0XUI1ber2qsNsKuk38j0iSsATeVOrrWFJIEr1G
$2a 10 10 10h7RiyAXP8JzWGsmAXGZy/uO6ASraQPNryVPl.11vMyUjhSCxS.Sde
$2a 10 10 10BCm3vuueGWdvjG3ciCUZB.6V9y6jMELHqB9iv2DwRJyOkR5jd…4S
$2a 10 10 10rO2894WmxRMtjHVzoYivyuzvje8BrAUjm8YLj3K.i4sQDvpWBtuuy
$2a 10 10 10jTosyN75hwKB3OSQCYY9YOIj6TYZG1FdJXfYCalTUuXpPiI5tv/P.
$2a 10 10 10p95j18H3yRABEScCE/2MqOqYt1ZqArdYhC87BVGEmQvn6znSqKw5G
$2a 10 10 10/y8FGBlvod1Dnq29c2scs.eGnYfvezZIZwfDHoXFfgIVA7H0T17pO
$2a 10 10 10k8IKAv4dBXhooEU8Qgo6E.PcrQ/ICymqNGLyE8Jfo4V1nk61GMeuy

6 方法安全
在配置類中添加注解:@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
接口都能訪問,但進(jìn)了接口不一定能訪問到接口里面的方法??!
【Controller層:】
@Autowired
MethodService methodService;
@GetMapping("/hello1")
public String hello1(){
return methodService.admin();
}
@GetMapping("/hello2")
public String hello2(){
return methodService.user();
}
@GetMapping("/hello3")
public String hello3(){
return methodService.hello();
}
【Service層:】
@Service
public class MethodService {
@PreAuthorize("hasRole('admin')")
public String admin() { //需要admin角色才能訪問
return "hello admin";
}
@Secured("ROLE_user")
public String user(){ //需要user角色才能訪問
return "hello user";
}
@PreAuthorize("hasAnyRole('admin','user')") //admin,user兩種權(quán)限
public String hello(){
return "hello hello";
}
}
7 基于數(shù)據(jù)庫的認(rèn)證
1、數(shù)據(jù)庫中創(chuàng)建三張表user、role、user_role



2、設(shè)置配置文件
# 應(yīng)用名稱 spring.application.name=SpringBoot_11_security # 應(yīng)用服務(wù) WEB 訪問端口 server.port=8080 #下面這些內(nèi)容是為了讓MyBatis映射 # 指定Mybatis的Mapper文件 mybatis.mapper-locations=classpath:mappers/*xml # 指定Mybatis的實(shí)體目錄 mybatis.type-aliases-package=com.example.mybatis.entity # 數(shù)據(jù)庫驅(qū)動(dòng): spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # 數(shù)據(jù)源名稱 spring.datasource.name=defaultDataSource # 數(shù)據(jù)庫連接地址 spring.datasource.url=jdbc:mysql://localhost:3306/【數(shù)據(jù)庫名稱】?serverTimezone=UTC spring.datasource.type=com.alibaba.druid.pool.DruidDataSource # 數(shù)據(jù)庫用戶名&密碼: spring.datasource.username=root spring.datasource.password=【數(shù)據(jù)庫密碼】
3、創(chuàng)建實(shí)體User、Role
package com.example.bean;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author 李飛林
* @ClassName User
* @mail 1961785612@qq.com
* @Description TODO
* @date 2022/8/4 21:46
*/
public class User implements UserDetails {
private Integer id;
private String username;
private String password;
private Boolean enabled;
private Boolean locked;
private List<Role> roles;
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public void setId(Integer id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
public Integer getId() {
return id;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() { //賬號(hào)是否未過期
return true;
}
@Override
public boolean isAccountNonLocked() { //賬號(hào)是否未鎖定
return !locked;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() { //是否可用
return enabled;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities=new ArrayList<>();
for (Role role:roles){
authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName()));//角色認(rèn)證以ROLE_開始
}
return authorities; //返回用戶所有角色
}
@Override
public String getPassword() {
return password;
}
}
package com.example.bean;
/**
* @author 李飛林
* @ClassName Role
* @mail 1961785612@qq.com
* @Description TODO
* @date 2022/8/4 21:49
*/
public class Role {
private Integer id;
private String name;
private String nameZh;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNameZh() {
return nameZh;
}
public void setNameZh(String nameZh) {
this.nameZh = nameZh;
}
}
4、編寫mapper層
UserMapper接口:
package com.example.mapper;
import com.example.bean.Role;
import com.example.bean.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* @author 李飛林
* @ClassName UserMapper
* @mail 1961785612@qq.com
* @Description TODO
* @date 2022/8/4 22:01
*/
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
List<Role> getUserRolesById(Integer id);
}
UserMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.mapper.UserMapper">
<select id="loadUserByUsername" resultType="com.example.bean.User">
select *
from user
where username = #{username};
</select>
<select id="getUserRolesById" resultType="com.example.bean.Role">
select *
from role
where id in (select rid from user_role where uid = #{id})
</select>
</mapper>
5、編寫service層:
package com.example.service;
import com.example.bean.User;
import com.example.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
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;
/**
* @author 李飛林
* @ClassName UserService
* @mail 1961785612@qq.com
* @Description TODO
* @date 2022/8/4 22:01
*/
@Service
public class UserService implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用戶不存在");
}
user.setRoles(userMapper.getUserRolesById(user.getId()));
return user;
}
}
6、security安全配置:
package com.example.config;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @author 李飛林
* @ClassName SecurityConfig
* @mail 1961785612@qq.com
* @Description TODO
* @date 2022/8/4 22:35
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserService userService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/dba/**").hasRole("dba")
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasRole("user")
.anyRequest().authenticated()//其他可訪問
.and()
.formLogin()
.permitAll()
.and()
.csrf().disable();
}
}
7、controller層接口調(diào)試:
package com.example.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 李飛林
* @ClassName HelloController
* @mail 1961785612@qq.com
* @Description TODO
* @date 2022/8/4 22:40
*/
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello security";
}
@GetMapping("/dba/hello")
public String dba() {
return "hello dba";
}
@GetMapping("/admin/hello")
public String admin() {
return "hello admin";
}
@GetMapping("/user/hello")
public String user() {
return "hello user";
}
}
8 角色繼承(在securityConfig中加入代碼段)
//角色繼承
@Bean
RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
String hierarchy = "ROLE_dba > ROLE_admin > ROLE_user"; //dba > admin > user
roleHierarchy.setHierarchy(hierarchy);
return roleHierarchy;
}
9 動(dòng)態(tài)配置權(quán)限
數(shù)據(jù)庫中的表結(jié)構(gòu)如下:





其中菜單表中已經(jīng)配置好對(duì)應(yīng)的路徑,后面需要從數(shù)據(jù)庫中加載:

一、查詢user用戶所具有的角色
1、編寫實(shí)體類User、Role、Menu:
User實(shí)現(xiàn)UserDetails接口,實(shí)現(xiàn)如下方法:
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities=new ArrayList<>();
for (Role role :
roles) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
2、編寫UserService:繼承UserDetailsService接口,實(shí)現(xiàn)loadUserByUsername方法
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService, UserDetailsService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(username); //根據(jù)登錄字符串獲獲取用戶名
if (user == null) {
throw new UsernameNotFoundException("用戶不存在");
} else {
user.setRoles(userMapper.getRolesById(user.getId())); //根據(jù)用戶名的ID查詢所具有的角色
}
return user;
}
}
3、編寫UserMapper接口:
@Mapper
public interface UserMapper extends BaseMapper<User> {
User loadUserByUsername(String username);
List<Role> getRolesById(Integer id);
}
4、編寫UserMapper.xml:
<select id="loadUserByUsername" resultType="com.lifeilin.pojo.User">
select *
from user
where username = #{username}
</select>
<select id="getRolesById" resultType="com.lifeilin.pojo.Role">
select *
from role
where id in (select rid from user_role where uid = #{id});
</select>至此,已經(jīng)從數(shù)據(jù)庫中獲取到登錄用戶user所具備的角色
二、配置SecurityConfig
1、在SecurityConfig類中配置登錄權(quán)限
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserServiceImpl userService;
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
//配置登錄
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
}
2、配置角色(從數(shù)據(jù)庫中動(dòng)態(tài)加載) 1 在config包中創(chuàng)建MyFilter.java過濾器
在config包中創(chuàng)建MyFilter.java過濾器,實(shí)現(xiàn)FilterInvocationSecurityMetadataSource接口,其主要作用是分析請(qǐng)求地址,請(qǐng)求地址必然是menu表中給出的標(biāo)準(zhǔn)地址(如果不是則進(jìn)行其他操作),根據(jù)請(qǐng)求地址分析出需要哪些角色
注意:這里需要提前從數(shù)據(jù)庫查詢出所有菜單以及對(duì)應(yīng)的角色。
補(bǔ)充:查詢菜單及對(duì)應(yīng)角色(使用Spring Cache作緩存)
1、導(dǎo)入緩存相關(guān)依賴
<!-- redis依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- cache依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2、需要簡單配置一下Redis,Redis的基本信息,另外,這里要用到Cache,因此還需要稍微配置一下Cache,如下:
## 配置redis #基本屬性 spring.redis.host=localhost spring.redis.port=6379 spring.redis.database=0 spring.redis.password= #配置cache名稱 spring.cache.cache-names=c1
另外,還需要在配置類上添加如下代碼,表示開啟緩存:

3、Service層緩存的使用
(1)在MenuServiceImpl類上使用@CacheConfig(cacheNames = “c1”)
這個(gè)注解在類上使用,用來描述該類中所有方法使用的緩存名稱,當(dāng)然也可以不使用該注解,直接在具體的緩存注解上配置名稱。
(2)在MenuServiceImpl類下getAllMenus()方法使用@Cacheable
這個(gè)注解一般加在查詢方法上,表示將一個(gè)方法的返回值緩存起來,默認(rèn)情況下,緩存的key就是方法的參數(shù),緩存的value就是方法的返回值。
@Service
@CacheConfig(cacheNames = "c1")
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
@Autowired
MenuMapper menuMapper;
//可以加緩存
@Cacheable
public List<Menu> getAllMenus() {
return menuMapper.getAllMenus();
}
}
@Mapper
public interface MenuMapper extends BaseMapper<Menu> {
List<Menu> getAllMenus();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lifeilin.mapper.MenuMapper">
<!-- 查詢所有menu-->
<!-- resultMap:填入配置的resultMap標(biāo)簽的id值 -->
<select id="getAllMenus" resultMap="BaseResultMap">
SELECT m.id,
m.pattern,
r.id AS rid,
r.NAME AS rname,
r.nameZh AS rnameZh
FROM menu AS m
LEFT JOIN menu_role AS mr ON m.id = mr.mid
LEFT JOIN role AS r ON mr.rid = r.id
</select>
<!-- resultMap最終還是要將結(jié)果映射到pojo上,type就是指定映射到哪一個(gè)pojo -->
<resultMap id="BaseResultMap" type="com.lifeilin.pojo.Menu">
<!-- 定義主鍵 ,非常重要。如果是多個(gè)字段,則定義多個(gè)id -->
<!-- property:主鍵在pojo中的屬性名 -->
<!-- column:主鍵在數(shù)據(jù)庫中的列名 -->
<id property="id" column="id"></id>
<!-- 定義普通屬性 -->
<result property="pattern" column="pattern"></result>
<!--collection中property的roles 對(duì)應(yīng)的是Role實(shí)體中的屬性-->
<collection property="roles" ofType="com.lifeilin.pojo.Role">
<id column="rid" property="id"/>
<result column="rname" property="name"/>
<result column="rnameZh" property="nameZh"/>
</collection>
</resultMap>
</mapper>
@Component
public class MyFilter implements FilterInvocationSecurityMetadataSource {
//路徑匹配符
AntPathMatcher pathMatcher = new AntPathMatcher();
@Autowired
MenuServiceImpl menuService;
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
String requestUrl = ((FilterInvocation) object).getRequestUrl();//獲取請(qǐng)求的地址
List<Menu> allMenus = menuService.getAllMenus();//查詢所有菜單
for (Menu menu : allMenus) {
if (pathMatcher.match(menu.getPattern(), requestUrl)) { //請(qǐng)求地址與菜單地址匹配上
List<Role> roles = menu.getRoles(); //獲取匹配成功的地址的角色
String[] rolesStr = new String[roles.size()];
for (int i = 0; i < roles.size(); i++) {
rolesStr[i] = roles.get(i).getName();
}
return SecurityConfig.createList(rolesStr);
}
}
return SecurityConfig.createList("ROLE_login"); //沒有匹配上,標(biāo)記符,額外處理
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
2、在config包中創(chuàng)建MyAccessDecisionManager類
在config包中創(chuàng)建MyAccessDecisionManager類,目的是通過上一步獲取了請(qǐng)求路徑需要哪些角色看看數(shù)據(jù)庫中是否具有該角色。
@Component
public class MyAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { //authentication知道有哪些角色,configAttributes知道需要哪些角色
//1、遍歷需要的角色
for (ConfigAttribute attribute : configAttributes) {
if ("ROLE_login".equals(attribute.getAttribute())){//請(qǐng)求地址都沒匹配上,說明是登陸后就可訪問的請(qǐng)求地址
if (authentication instanceof AnonymousAuthenticationToken){ //匿名用戶(沒登陸)
throw new AccessDeniedException("非法請(qǐng)求");
}else {
return;
}
}
//2、獲取所具備的角色
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for (GrantedAuthority authority : authorities) {
if (authority.getAuthority().equals(attribute.getAttribute())){//如果具備所需要的角色
return;
}
}
}
throw new AccessDeniedException("非法請(qǐng)求");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
3、在SecurityConfig引入myAccessDecisionManager + myFilter
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
@Override
public <O extends FilterSecurityInterceptor> O postProcess(O object) {
object.setAccessDecisionManager(myAccessDecisionManager);//
object.setSecurityMetadataSource(myFilter);//
return object;
}
})
.and()
.formLogin()
.permitAll()
.and()
.csrf().disable();
}
到此這篇關(guān)于Spring Security權(quán)限管理的文章就介紹到這了,更多相關(guān)Spring Security權(quán)限管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用Thread創(chuàng)建多線程并啟動(dòng)操作示例
這篇文章主要介紹了Java使用Thread創(chuàng)建多線程并啟動(dòng)操作,結(jié)合實(shí)例形式分析了Java基于Thread類的多線程定義與啟動(dòng)簡單操作技巧,需要的朋友可以參考下2018-06-06
Java讀寫pdf文件的詳細(xì)實(shí)現(xiàn)方法
最近公司的項(xiàng)目中需要操作pdf文件,所以這里給大家總結(jié)下方法,這篇文章主要給大家介紹了關(guān)于Java讀寫pdf文件的詳細(xì)實(shí)現(xiàn)方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09
idea配置maven環(huán)境時(shí)maven下載速度慢的解決方法
我們?cè)趇dea配置maven環(huán)境的時(shí)候會(huì)發(fā)現(xiàn)maven更新慢的現(xiàn)象,解決辦法就是下載國內(nèi)的鏡像包,完美解決下載速度慢的問題,文中有詳細(xì)的具體操作方法,并通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-02-02

