SpringBoot框架:集成Security完成认证鉴权

一、导入依赖包

  1、导入security相关包:

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-security</artifactId>
</dependency>

二、基础部署

  1、HelloController.java:

  在Controller层里编写一些简单的接口,用于测试认证和鉴权。

package com.example.demo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello(){
        return "hello";
    }
    
    @RequestMapping("/404")
    public String hello404(){
        return "404";
    }
    
    @RequestMapping("/403")
    public String hello403(){
        return "403";
    }
    
    @RequestMapping("/500")
    public String hello500(){
        return "500";
    }
}

  2、UserPo.java:

  用户实体类,用来存储用户信息和用户所拥有的的角色权限。

package com.example.demo.po;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class UserPo implements Serializable, UserDetails {
    /** 主键id */
    private Long id;
    /** 用户名 */
    private String userName;
    /** 密码 */
    private String password;
    /** 昵称 */
    private String nickName;
    /** 用户是否可用 */
    private boolean enabled;
    /** 角色集合 */
    private List<RolePo> roles;
    /** 注册时间 */
    private String regTime;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public String getUsername() {
        return userName;
    }

    /**
     * 获取角色权限
     * @return
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorities = new ArrayList<>();
        for (RolePo role : roles) {
            authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
        }
        return authorities;
    }


    /**
     * 账户未使用
     * @return
     */
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    /**
     * 账户未锁定
     * @return
     */
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    /**
     * 权限未启用
     * @return
     */
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    @Override
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }


    @Override
    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public List<RolePo> getRoles() {
        return roles;
    }

    public void setRoles(List<RolePo> roles) {
        this.roles = roles;
    }

    public String getRegTime() {
        return regTime;
    }

    public void setRegTime(String regTime) {
        this.regTime = regTime;
    }

}

  该类实现UserDetails接口,这个是Sercurity里自带的类,而且实现其中的各个方法,像getAuthorities这个方法是比较重要的,要将自己从数据库里读出的用户角色进行处理,带上角色前缀“ROLE_”,用于鉴权的hasRole方法使用。

  类似于isAccountNonExpired、isAccountNonLocked、isCredentialsNonExpired这些方法,要返回true,否则在登录时会提示用户被锁住等信息。

  3、UserService.java:

  UserService直接继承UserDetailsService类,在实现类里对该类的方法进行重写。

package com.example.demo.service;

import org.springframework.security.core.userdetails.UserDetailsService;

public interface UserService extends UserDetailsService {

}

  4、UserServiceImpl.java:

  UserServiceImpl实现UserDetailsService中的loadUserByUsername

package com.example.demo.service.impl;

import com.example.demo.mapper.RoleMapper;
import com.example.demo.mapper.UserMapper;
import com.example.demo.po.RolePo;
import com.example.demo.po.UserPo;
import com.example.demo.service.UserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;
    @Autowired
    RoleMapper roleMapper;

    /**
     * 根据用户名获取用户信息
     * @param s
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        //参数为空,返回空
        if(StringUtils.isEmpty(s)){
            return null;
        }
        //参数不为空,返回获取到的用户信息
        UserPo userPo = userMapper.getUserByUserName(s);
        //填充用户角色信息
        List<RolePo> rolePos = roleMapper.getRolesByUserId(userPo.getId());
        userPo.setRoles(rolePos);
        userPo.getAuthorities();
        return userPo;
    }
}

  根据用户名获取用户信息,并通过用户与角色的关联关系取得角色信息,使用getAuthorities方法将角色配给用户。

  5、WebSecurityConfig.java:

  该类继承WebSecurityConfigurerAdapter适配器,添加加密工具以及配置相关接口的开放和拦截。

package com.example.demo.config;

import com.example.demo.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;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserService userService;

    /**
     * 获取加密工具
     * @return
     */
    @Bean
    public PasswordEncoder getPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(userService)
                .passwordEncoder(getPasswordEncoder());
    }

    /**
     * 处理接口的开放和拦截
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http.authorizeRequests()
                //开放拦截
                .antMatchers("/500").permitAll()
                .antMatchers("/403").permitAll()
                .antMatchers("/404").permitAll()
                .antMatchers("/hello").hasRole("admin")
                //其他任何请求都要进行身份认证
                .anyRequest()
                .authenticated()
                .and()
                //表单提交数据
                .formLogin()
                //配置登录接口
                .loginProcessingUrl("/login")
                .and()
                //关闭跨站请求伪造保护
                .csrf().disable();
    }
}

  按照上面的配置,现在404、403、500接口都是开放的,认证之后即可访问,不做权限拦截。

  但是hello这个接口需要登录认证之后,再进行权限判断,即角色字段要与hasRole中的一致。

原文地址:https://www.cnblogs.com/guobin-/p/14207032.html