SpringSecurity学习之自定义用户认证

  SpringSecurity给我们提供了一套最基本的认证方式,可是这种方式远远不能满足大多数系统的需求。不过好在SpringSecurity给我们预留了许多可扩展的接口给我们,我们可以基于这些接口实现自己的认证方式。

一、前期准备工作

1.1、创建示例数据库

Student表:

create table student
(
    id int auto_increment
        primary key,
    stuName varchar(8) null,
    password varchar(16) null,
    joinTime datetime null,
    clz_id int null
)
;

Classes(班级)表:

create table classes
(
    id int auto_increment
        primary key,
    clz_name varchar(16) not null
)
;

1.2、添加相关依赖

compile group: 'mysql', name: 'mysql-connector-java'
compile group: 'org.springframework.security', name: 'spring-security-taglibs'
compile('org.springframework.boot:spring-boot-starter-jdbc')

二、实现步骤

2.1  定义Student类

package com.bdqn.lyrk.security.study.app.pojo;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

import java.sql.Timestamp;
import java.util.Collection;

public class Student extends User {

    private Timestamp joinTime;

    public Timestamp getJoinTime() {
        return joinTime;
    }

    public void setJoinTime(Timestamp joinTime) {
        this.joinTime = joinTime;
    }

    public Student(String username, String password, Collection<? extends GrantedAuthority> authorities) {
        super(username, password, authorities);
    }

}
View Code

  在这里定义的类继承User,User是SpringSecurity里的一个类,用以描述一个用户和其最基本的属性,当然我们要扩展它的用户我们也可以实现UserDetails接口

2.2 实现UserDetailsService

package com.bdqn.lyrk.security.study.app.service;

import com.bdqn.lyrk.security.study.app.pojo.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class UserService implements UserDetailsService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User.UserBuilder users = User.withDefaultPasswordEncoder();
        Map<String, Object> map = jdbcTemplate.queryForMap("select t.clz_name,t1.stuName,t1.password,t1.joinTime from student t1 inner  join classes t on t.id = t1.clz_id where stuName = ?", username);
        Timestamp joinTime = null;
        if (map != null && map.size() > 0) {
            String stuName = (String) map.get("stuName");
            String password = (String) map.get("password");
            joinTime = (Timestamp) map.get("joinTime");
            String clzName = (String) map.get("clz_name");
            users.password(password);
            users.username(stuName);
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority(clzName);
            List<GrantedAuthority> list = new ArrayList<>();
            list.add(authority);
            users.authorities(list);
        }
        UserDetails userDetails = users.build();
        Student student = new Student(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
//        UserDetails userDetails = User.withDefaultPasswordEncoder().
        student.setJoinTime(joinTime);
        return student;
    }
}
View Code

  在这个接口里我们要实现根据用户名查找用户的方法,那么一般情况下我们都会根据自己系统的用户表来获取用户信息,这里面注意几个方面:

  1)需要设置PasswordEncoder 

  2) 需要设置其角色信息,那么在这里我用班级来表示用户的角色

  3)用户的三个重要属性就是 用户名,密码与权限

扫描二维码关注公众号,回复: 1550135 查看本文章

2.3 改造WebSecurityConfig

package com.bdqn.lyrk.security.study.app.config;

import com.bdqn.lyrk.security.study.app.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * spring-security的相关配置
 *
 * @author chen.nie
 * @date 2018/6/7
 **/
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /*
            1.配置静态资源不进行授权验证
            2.登录地址及跳转过后的成功页不需要验证
            3.其余均进行授权验证
         */
        http.
                authorizeRequests().antMatchers("/static/**").permitAll().
                and().authorizeRequests().antMatchers("/user/**").hasRole("7022").
                and().authorizeRequests().anyRequest().authenticated().
                and().formLogin().loginPage("/login").successForwardUrl("/toIndex").permitAll()
                .and().logout().logoutUrl("/logout").invalidateHttpSession(true).deleteCookies().permitAll()
        ;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //设置自定义userService
        auth.userDetailsService(userService);
    }
}
View Code

在这里主要做以下处理:

 1)针对于/user/**路径的请求需要设置对应的权限

 2) 做用户注销的处理,用户注销时需要销毁session与cookie

 3)配置自定义UserDetailService

2.4、改造index.jsp

<%--
  Created by IntelliJ IDEA.
  User: chen.nie
  Date: 2018/6/8
  Time: 上午9:56
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
欢迎:${user.username}
<sec:authorize access="hasRole('7022')">
    加入时间:${user.joinTime}
</sec:authorize>
<form action="/logout" method="post">
    <input type="submit" value="退出" />
    <sec:csrfInput/>
</form>

</body>
</html>

  在这里面我们使用spring对security标签的支持判断当前用户是否有对应的角色,另外我们在处理登出操作时必须为post提交且有对应的token防止csrf

猜你喜欢

转载自www.cnblogs.com/niechen/p/9163590.html