zeromemos
最好的学习方法就是输出所学的知识

SpringSecurity前后端分离登录认证

主要通过上图中的AuthenticationManager手动委托框架进行认证。


首先Maven中要加入依赖

        <!-- SpringSecurity权限管理依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

加入配置类WebSecurityConfigurer

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) //开启注解权限认证
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {


//将AuthenticationManager暴露出去,以便于后面在其他类里能直接注入 @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } //访问权限配置 @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeHttpRequests() //放行的请求 .mvcMatchers("/", "/user/login") .permitAll() //其他全部拦截 .anyRequest().authenticated(); //关闭csrf跨站请求伪造 http.csrf().disable(); //不通过session来存储和获取会话 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); } }

因为要前后端分离,我们要将会话数据存在Redis里,所以这边要关闭session存储会话的功能,并且放行登录接口/user/login

http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

并且暴露了AuthenticationManager,以便于后面在其他类里能直接注入。


创建一个实现了UserDetails接口的MySecurityUser,方便后面存取需要的用户信息。

public class MySecurityUser extends User {

    //自己的User实体类,方便后面存取需要的用户信息
    private SysUser sysUser;
    //分别将用户、密码和权限集合传到父类的构造函数里
    public MySecurityUser(SysUser sysUser, Collection<? extends GrantedAuthority> authorities) {
        super(sysUser.getUsername(), sysUser.getPassword(), authorities);
        this.sysUser = sysUser;
    }

    public SysUser getSysUser() {
        return sysUser;
    }

    public void setSysUser(SysUser sysUser) {
        this.sysUser = sysUser;
    }
}

创建一个实现了UserDetailsService接口的MyUserDetailsService类,用于自定义从数据库获取用户信息功能。下面的sysUserService.getByUsername("admin")就是根据用户名从数据库获取用户对象。

@Component
public class MyUserDetailsService implements UserDetailsService {

    private final SysUserService sysUserService;

    public MyUserDetailsService(SysUserService sysUserService) {
        this.sysUserService = sysUserService;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        //查询用户
        SysUser sysUser = sysUserService.getByUsername("admin");

        return new MySecurityUser(sysUser, new ArrayList<GrantedAuthority>());
    }
}

创建登录接口方法,这边返回的是jwt生成的token。

@RestController
@RequestMapping("/user")
public class SysUserController {

    private final SysUserService sysUserService;

    public SysUserController(SysUserService sysUserService) {
        this.sysUserService = sysUserService;
    }


    @PostMapping("login")
    public Map<String, String> login(String username, String password) {
        String token = sysUserService.doLogin(username, password);
        Map<String, String> map = new HashMap<>();
        map.put("token", token);
        return map;
    }
}

service里的实现方法如下

/**
     * 进行登录
     *
     * @param username 用户名
     * @param password 密码
     * @return 登录成功返回token 登录失败直接交给异常处理
     */
    @Override
    public String doLogin(String username, String password) {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        Authentication authenticate = null;
        try {
            authenticate = authenticationManager.authenticate(authenticationToken);
        } catch (AuthenticationException e) {
            System.out.println("认证失败");
            e.printStackTrace();
        }
        if (authenticate == null) {
            throw new RuntimeException("登录失败");
        }
        MySecurityUser mySecurityUser = (MySecurityUser)authenticate.getPrincipal();
        Map<String, String> map = new HashMap<>();
        map.put("username", mySecurityUser.getUsername());
        String token = JWTUitls.getToken(map);
        return token;
    }

这里将前端传来的用户名和密码手动创建UsernamePasswordAuthenticationToken对象,然后交给authenticationManager.authenticate()方法进行认证,认证失败会抛出异常,进行捕获处理即可。认证成功就使用jwt工具类生成token返回给用户。

评论区

关于我们

本站主要用于记录个人学习笔记,网站开发中,如需以前站内资料请加QQ群272473835索取。注册账号仅提供回帖功能,可不注册!

微信公众号