溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring?Security如何使用數據庫登錄認證授權

發布時間:2022-01-05 19:04:07 來源:億速云 閱讀:451 作者:柒染 欄目:開發技術

本篇文章給大家分享的是有關Spring Security如何使用數據庫登錄認證授權,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

一、搭建項目環境

1、創建 RBAC五張表

RBAC,即基于角色的權限訪問控制(Role-Based Access Control),就是用戶通過角色與權限進行關聯。
在這種模型中,用戶與角色之間,角色與權限之間,一般者是多對多的關系。

MySQL數據庫中,創建如下幾個表:

DROP TABLE IF EXISTS sys_user;
CREATE TABLE sys_user(
    id BIGINT NOT NULL AUTO_INCREMENT  COMMENT '主鍵id' ,
    username VARCHAR(60)    COMMENT '用戶名' ,
    password VARCHAR(255)    COMMENT '密碼' ,
    status tinyint(1)    COMMENT '用戶狀態,1-開啟-0禁用' ,
    password_non_expired tinyint(1)    COMMENT '密碼是否失效,1-可用,0-失效' ,
    PRIMARY KEY (id)
)  COMMENT = '用戶表';

DROP TABLE IF EXISTS sys_role;
CREATE TABLE sys_role(
    id BIGINT NOT NULL AUTO_INCREMENT  COMMENT '主鍵id' ,
    role_name VARCHAR(64) NOT NULL   COMMENT '角色名' ,
    role_desc VARCHAR(64) NOT NULL   COMMENT '角色描述' ,
    PRIMARY KEY (id)
)  COMMENT = '角色表';

DROP TABLE IF EXISTS sys_permission;
CREATE TABLE sys_permission(
    id BIGINT NOT NULL AUTO_INCREMENT  COMMENT '主鍵id' ,
    parent_id BIGINT    COMMENT '父id' ,
    permission_name VARCHAR(64)    COMMENT '菜單名稱' ,
    permission_url VARCHAR(255)    COMMENT '菜單地址' ,
    PRIMARY KEY (id)
)  COMMENT = '權限表';

DROP TABLE IF EXISTS sys_user_role;
CREATE TABLE sys_user_role(
    id BIGINT NOT NULL AUTO_INCREMENT  COMMENT '主鍵id' ,
    user_id BIGINT NOT NULL   COMMENT '用戶id' ,
    role_id BIGINT    COMMENT '角色id' ,
    enabled tinyint(1)   DEFAULT 1 COMMENT '是否有效' ,
    PRIMARY KEY (id)
)  COMMENT = '用戶角色關聯表';

DROP TABLE IF EXISTS sys_role_permission;
CREATE TABLE sys_role_permission(
    id BIGINT NOT NULL AUTO_INCREMENT  COMMENT '主鍵id' ,
    role_id BIGINT NOT NULL   COMMENT '角色id' ,
    permission_id BIGINT    COMMENT '權限id' ,
    PRIMARY KEY (id)
)  COMMENT = '角色權限表';

Spring?Security如何使用數據庫登錄認證授權

2、創建項目

創建 Mavne 項目,Springboot + Spring Security + MyBatis + MySQL + jsp。

1)配置文件如下

server:
  port: 9090

# jsp配置
spring:
  mvc:
    view:
      prefix: /pages/
      suffix: .jsp
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/security_authority?useUnicode=true;characterEncoding=utf8;useSSL=true;serverTimezone=GMT
    username: root
    password: 123456

# mybatis配置
mybatis:
  configuration:
    map-underscore-to-camel-case: true
  mapper-locations: classpath:mybatis/mapper/*.xml

logging:
  level:
    com.charge.learn.springsecurity.springboot.security.jsp.dao: debug

2)啟動類

@SpringBootApplication
@MapperScan("com.charge.learn.springsecurity.springboot.security.jsp.dao")
public class SpringSecurityApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringSecurityApplication.class, args);
    }
}

Spring?Security如何使用數據庫登錄認證授權

二、整合 Spring Security實現用戶認證

1、后端整合

1.1 用戶

Spring Security的用戶對象是 UserDetail類型,Spring Security在認證流程中只認 UserDetail用戶。

  • 通過 UserDetailsService的 loadUserByUsername方法獲取 UserDetail用戶。

  • 認證成功之后,調用的是這個帶有三個參數的 UsernamePasswordAuthenticationToken構造方法,將 角色信息添加到了ArrayList<GrantedAuthority>集合中。

  • 在 successfulAuthentication 方法中,將認證信息存儲到了SecurityContext中。

Spring?Security如何使用數據庫登錄認證授權

UserDetail接口的方法(根據用戶業務來處理這幾個值)。

  • boolean enabled 賬戶是否可用

  • boolean accountNonExpired 賬戶是否失效

  • boolean credentialsNonExpired 賬戶密碼是否失效

  • boolean accountNonLocked 賬戶是否鎖定

  • Collection<? extends GrantedAuthority> getAuthorities() 獲取賬戶的所有權限(用戶角色)

注意:四個布爾類型的參數都為 true時,然后成功,否則,有一個為 false,就會認證失敗。

所以,我們可以將我們的用戶封裝成 UserDetail對象。
這里我們讓用戶對象實現 UserDetail接口,那么我們用戶就屬于 UserDetail類型的用戶,然后實現接口的方法。

public class SysUser implements UserDetails {

    private Long id;
    private String username;
    private String password;
    private Boolean status; //用戶狀態,1-開啟-0禁用
    private Boolean passwordNonExpired; //密碼是否失效,1-可用,0-失效
    /**
     * 用戶關聯的所有角色
     */
    private List<SysRole> roles = new ArrayList<>();

//get、set方法

    //標記該字段不做json處理
    @JsonIgnore
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return roles;
    }

    @JsonIgnore
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @JsonIgnore
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @JsonIgnore
    @Override
    public boolean isCredentialsNonExpired() {
        return passwordNonExpired == null ? false : passwordNonExpired;
    }

    @JsonIgnore
    @Override
    public boolean isEnabled() {
        return status == null ? false : status;
    }

}

1.2 角色

Spring Security的權限對象是 GrantedAuthority類型。通過它的值來實現權限管理的。

Spring?Security如何使用數據庫登錄認證授權

所以,我們讓角色對象實現GrantedAuthority接口,那么我們角色就屬于 GrantedAuthority類型,然后實現接口的方法。
上面用戶可以直接將 角色添加到 Collection<? extends GrantedAuthority>集合中。

public class SysRole implements GrantedAuthority {

    private Long id;
    private String roleName;
    private String roleDesc;

//get、set方法

    //標記該字段不做json處理
    @JsonIgnore
    @Override
    public String getAuthority() {
        return roleName;
    }

}

1.3 SysUserService接受繼承UserDetailsService類

Spring Security在認證流程中通過 UserDetailsService的 loadUserByUsername方法獲取 UserDetail用戶。

Spring?Security如何使用數據庫登錄認證授權

所以,我們讓 UserService接口繼承 UserDetailsService類,然后重寫 loadUserByUsername方法。

在 loadUserByUsername方法中,獲取我們的用戶信息( UserDetail類型),記得將用戶關聯的角色也賦值為用戶信息。

public interface SysUserService extends UserDetailsService {

    void save(SysUser user);
}
@Service
@Transactional
public class SysUserServiceImpl implements SysUserService {

	@Autowired
	private SysUserMapper sysUserMapper;

	@Autowired
	private SysRoleMapper sysRoleMapper;

	@Autowired
	private BCryptPasswordEncoder passwordEncoder;

	@Override
	public void save(SysUser sysUser) {
		// 將密碼加密入庫
		sysUser.setPassword(passwordEncoder.encode(sysUser.getPassword()));
		sysUserMapper.insert(sysUser);
	}

	/**
	 * 認證業務
	 *
	 * @param username
	 *            - 用戶在瀏覽器輸入的用戶名
	 * @return UserDetails - Spring Security的用戶對象,返回 null表示認證失??!
	 * @throws UsernameNotFoundException
	 */
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		/**
		 * 用戶信息和角色信息可以一步關聯查詢到位得到SysUser,我這里分開查詢
		 */
		// 1.查詢用戶
		SysUser sysUser = sysUserMapper.getByUsername(username);
		if (sysUser == null) {
			return null;
		}
		// 2.獲取用戶關聯的所有角色
		List<SysRole> sysRoles = sysRoleMapper.listAllByUserId(sysUser.getId());
		sysUser.setRoles(sysRoles);
		System.out.println("====> sysUser=" + sysUser.toString());
		return sysUser;
	}
}

mapper.xml中的幾個方法

  <select id="getByUsername" resultMap="BaseResultMap">
    select id, username, password, status, password_non_expired from sys_user where username = #{username}
  </select>

  <select id="listAllByUserId" resultMap="BaseResultMap">
    SELECT r.id, r.role_name role_name, r.role_desc role_desc
    FROM sys_role r, sys_user_role ur
    WHERE r.id = ur.role_id AND ur.user_id = #{userId}
  </select>

1.4 創建 SpringSecurity配置類

自定義一個配置類,添加@EnableWebSecurity注解,并繼承WebSecurityConfigurerAdapter類。然后就擁有了 SpringSecutiry的所有默認配置。我們也可以修改配置。

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SysUserService userService;

    // 加密對象注入IOC容器
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    // 1.指定認證對象的來源(內存或者數據庫),指定加密方式
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }

    //2. SpringSecurity配置相關信息
    @Override
    public void configure(HttpSecurity http) throws Exception {
        // 釋放靜態資源,指定攔截規則,指定自定義的認證和退出頁面,csrf配置等
        http.authorizeRequests()
                // 指定攔截規則
                .antMatchers("/login.jsp", "failer.jsp", "/css/**", "/img/**", "/plugins/**").permitAll()  //釋放這些資源,不攔截
                .antMatchers("/**").hasAnyRole("USER", "ADMIN") //所有資源都需要這些角色中的一個
                .anyRequest().authenticated()  //其他請求,必須認證通過之后才能訪問
                .and()  // 表示新的一個配置開始
                // 指定自定義的認證頁面
                .formLogin()
                .loginPage("/login.jsp")
                .loginProcessingUrl("/login")
                .successForwardUrl("/index.jsp")
                .failureForwardUrl("/failer.jsp")
                .permitAll() // 釋放這些資源,不攔截登錄
                .and()
                // 指定自定義的退出頁面
                .logout()
                .logoutSuccessUrl("/logout")
                .invalidateHttpSession(true) // 清楚session
                .logoutSuccessUrl("/login.jsp")
                .permitAll()
                //.and()
//                禁用csrf配置,默認開啟的(一般不寫,頁面要加csrf),這里我們測試下
//                .and()
//                .csrf()
//                .disable()
                ;
    }

主要配置信息如下:

  • 指定認證對象 SysUserService (UserDetailsService類型)

  • 指定了用戶密碼使用的加密對象

  • SpringSecurity配置相關信息,比如:指定攔截規則,指定自定義的認證頁面,csrf等。

2、前端整合

在 Spring Security 中,如果我們不做任何配置,默認的登錄頁面和登錄接口的地址都是 /login,即默認會存在如下兩個請求:

  • GET http://localhost:8080/login

  • POST http://localhost:8080/login

如果是 GET 請求表示你想訪問登錄頁面,如果是 POST 請求,表示你想提交登錄數據。默認的表單字段為 username和password。

SpringSecurity 默認 是開啟 csrf防護機制。
所以,在自定義的表單上添加上 _csrf隱藏input(必須要寫在form表單里面)。

引入 security標簽庫
<%@taglib uri="http://www.springframework.org/security/tags" prefix="security"%>
<security:csrfInput/>

啟動項目,登錄認證訪問ok.

三、整合 Spring Security實現用戶授權

認證過程獲取用戶信息時,我們已經把用戶關聯的角色信息設置到了 UserDetails中,所以,我們只需要分配 資源訪問的角色就可以了。

1、后端

1.1 開啟 Spring Security權限控制

Spring Security可以通過注解的方式來控制類或者方法的訪問權限。支持開啟權限控制的注解類型如下:

  • jsr250-annotations:表示支持 jsr250-api的注解

  • pre-post-annotations:表示支持 spring表達式注解

  • secured-annotations:這才是 Spring Security提供的注解

Spring?Security如何使用數據庫登錄認證授權

在實際開發中,用一類即可,三個都開啟也沒關系。
在 SpringSecurity配置類上 添加 @EnableGlobalMethodSecurity注解,表示開啟 Spring Security權限控制,這里我們三類都開啟了。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true, prePostEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    ...
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true, prePostEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
...

1.2 在角色對應類或者方法上添加權限注解

1.2.1 使用 Spring Security注解

  • @Secured({“ROLE_ADMIN”,“ROLE_PRODUCT”})

@Controller
@RequestMapping("/user")
@Secured("ROLE_ADMIN") 	//表示當前類中所有方法需要 ROLE_ADMIN才能訪問
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/findAll")
    public String findAll(Model model){
        List<SysUser> list = userService.findAll();
        model.addAttribute("list", list);
        return "user-list";
    }
    。。。
 }

1.2.2 使用 Spring表達式注解

  • @PreAuthorize(“hasAnyRole(&lsquo;ROLE_ADMIN&rsquo;,&lsquo;ROLE_PRODUCT&rsquo;)”)

@Controller
@RequestMapping("/product")
public class ProductController {
    
    @RequestMapping("/findAll")
    //表示當前類中findAll方法需要 ROLE_ADMIN或者 ROLE_PRODUCT才能訪問
    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_PRODUCT')") 
    public String findAll(){
        return "product-list";
    }
}

1.2.3 使用 JSR-250注解

  • @RolesAllowed({“ROLE_ADMIN”,“ROLE_User”})

@Controller
@RequestMapping("/order")
@RolesAllowed({"ROLE_ADMIN","ROLE_USER"}) //表示當前類中所有方法都需要ROLE_ADMIN或者ROLE_User才能訪問
public class OrderController {
    
    @RequestMapping("/findAll")
    public String findAll(){
        return "order-list";
    }
}

2、前端

在jsp業頁面中,對每個菜單資源通過 SpringSecurity標簽庫指定訪問所需的角色。

<%@taglib uri="http://www.springframework.org/security/tags" prefix="security" %>
<!-- 指定訪問所需角色 -->
<security:authorize access="hasAnyRole('ROLE_ADMIN', '等等')">

啟動項目,通過不同的用戶登錄,授權訪問ok.

以上就是Spring Security如何使用數據庫登錄認證授權,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女