赞
踩
user表,记录用户信息
role表,记录角色清单
user_role表,用户角色对照表
- <!--Spring Security-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <!--mybatis-->
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>2.2.0</version>
- </dependency>
- <!--Mysql-->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <scope>runtime</scope>
- </dependency>
- <!--Thymeleaf-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-thymeleaf</artifactId>
- </dependency>

因为使用Mybatis,所以build要添加XML资源目录,否则编译会缺少UserMapper.XML。
- <resources>
- <resource>
- <!-- XML默认是放在resource下面,如果有自定义,需要把resource加上 -->
- <directory>src/main/java</directory>
- <includes>
- <include>**/*.xml</include>
- </includes>
- </resource>
- <resource>
- <directory>src/main/resources</directory>
- </resource>
- </resources>
- #datasource mybatis配置--------------------------------
- spring.datasource.url=jdbc:mysql://127.0.0.1:3306/jpa?characterEncoding=UTF-8
- spring.datasource.username=root
- spring.datasource.password=12345678
- spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
- #datasource mybatis配置--------------------------------
- #thymeleaf配置--------------------------------
- spring.thymeleaf.cache=true
- spring.thymeleaf.checktemplate=true
- spring.thymeleaf.check-template-location=true
- spring.thymeleaf.encoding=UTF-8
- spring.thymeleaf.servlet.content-type=text/html
- spring.thymeleaf.suffix=.html
- spring.thymeleaf.prefix=classpath:/templates/
- #Thymeleaf配置--------------------------------
这里通过用户注册接口registerController去数据库查询角色清单(role表),将查询结果写入roles集合中,通过Thymeleaf模板进行调用并加入select-option选择列表,供用户注册时选择某一角色。
- <!DOCTYPE html>
- <html lang="en" xmlns:th="http://www.thymeleaf.org">
- <head>
- <meta charset="UTF-8">
- <title>新用户注册</title>
- </head>
- <body>
- <h2 align="center">新用户注册</h2>
- <hr width="40%" color="gray"/>
- <form action="/doregister" method="post" enctype="application/x-www-form-urlencoded">
- <table width="40%" bgcolor="gray" align="center">
- <tr>
- <td align="right">用户名:</td>
- <td>
- <input type="text" name="username" size="25px" maxlength="10" placeholder="请输入用户名最长10位" required/>
- </td>
- </tr>
- <tr>
- <td align="right">密码:</td>
- <td>
- <input type="password" name="password" size="25px" maxlength="20" placeholder="请输入密码最长20位" required>
- </td>
- </tr>
- <tr>
- <td align="right">角色:</td>
- <td>
- <label>
- <select name="role">
- <option>--请选择角色--</option>
- <option th:each="role:${roles}"
- th:value="${role.id}"
- th:text="${role.nameZH}"
- th:selected="${role==role.id}"></option>
- </select>
- </label>
- </td>
- </tr>
- <tr>
- <td align="right">
- <input type="submit" value="提交注册">
- </td>
- <td>
- </td>
- </tr>
- </table>
- </form>
- </body>
- </html>

- package com.example.springsecurity.Entity;
- import java.io.Serializable;
- public class Role implements Serializable {
- 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;
- }
- }

该实体类主要用于用户登录,需要使用标准的UserDetails接口。
- package com.example.springsecurity.Entity;
- 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;
- public class User implements UserDetails {
- private Integer id;
- private String username;
- private String password;
- private Boolean enabled;
- private Boolean locked;
- private List<Role> roles;
- @Override
- public Collection<? extends GrantedAuthority> getAuthorities(){
- List<SimpleGrantedAuthority> authorities= new ArrayList<>();
- for (Role r:roles){
- authorities.add(new SimpleGrantedAuthority(r.getName()));
- }
- return authorities;
- }
- @Override
- public String getPassword(){
- return password;
- }
- @Override
- public String getUsername(){
- return username;
- }
- @Override
- public boolean isAccountNonExpired(){
- return true;
- }
- @Override
- public boolean isAccountNonLocked(){
- return true;
- }
- @Override
- public boolean isCredentialsNonExpired(){
- return true;
- }
- @Override
- public boolean isEnabled(){
- return true;
- }
- public Integer getId() {
- return id;
- }
- 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 Boolean getEnabled() {
- return enabled;
- }
- public void setEnabled(Boolean enabled) {
- this.enabled = enabled;
- }
- public Boolean getLocked() {
- return locked;
- }
- public void setLocked(Boolean locked) {
- this.locked = locked;
- }
- public List<Role> getRoles() {
- return roles;
- }
- public void setRoles(List<Role> roles) {
- this.roles = roles;
- }
- }

该实体类主要用于用户注册。
- package com.example.springsecurity.Entity;
- public class UserRegister {
- private Integer id;
- private String username;
- private String password;
- private Boolean enabled;
- private Boolean locked;
- private Integer role;
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- public Boolean getEnabled() {
- return enabled;
- }
- public void setEnabled(Boolean enabled) {
- this.enabled = enabled;
- }
- public Boolean getLocked() {
- return locked;
- }
- public void setLocked(Boolean locked) {
- this.locked = locked;
- }
- public Integer getRole() {
- return role;
- }
- public void setRole(Integer role) {
- this.role = role;
- }
- }

主要包含UserMapper.xml和UserMapper interface,包含:
loadUserByUsername方法,通过用户名查询用户
getUserRolesByUid方法,通过用户ID获取用户所有角色
addUserByUsername方法,通过UserRegister实体类注册新用户
getAllRole方法,获取当前系统所有角色
addRole方法,通过用户ID和角色ID,给用户添加角色
- <?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.springsecurity.Repository.UserMapper">
- <select id="loadUserByUsername" resultType="com.example.springsecurity.Entity.User">
- select * from user where username=#{username}
- </select>
- <select id="getUserRolesByUid" resultType="com.example.springsecurity.Entity.Role">
- select * from role r,user_role ur where r.id=ur.rid and ur.uid=#{id}
- </select>
- <insert id="addUserByUsername" parameterType="com.example.springsecurity.Entity.UserRegister">
- insert into user(username,password,enabled,locked) values(#{username},#{password},#{enabled},#{locked})
- </insert>
- <select id="getAllRole" resultType="com.example.springsecurity.Entity.Role">
- select * from role
- </select>
- <insert id="addRole">
- insert into user_role(uid,rid) values(#{uid},#{rid})
- </insert>
- </mapper>

- package com.example.springsecurity.Repository;
- import com.example.springsecurity.Entity.Role;
- import com.example.springsecurity.Entity.User;
- import com.example.springsecurity.Entity.UserRegister;
- import org.apache.ibatis.annotations.Mapper;
- import java.util.List;
- @Mapper
- public interface UserMapper {
- User loadUserByUsername(String username);
- List<Role> getUserRolesByUid(Integer id);
- int addUserByUsername(UserRegister userRegister);
- List<Role> getAllRole();
- int addRole(Integer uid,Integer rid);
- }
是上述接口方法的实现类,包含:
loadUserByUsername实现方法,用于查询用户以及所具有的角色
addUserByUsername实现方法,用于实现用户注册以及角色注册
getAllRole实现方法,用户查询所有角色清单
- package com.example.springsecurity.Service;
- import com.example.springsecurity.Entity.Role;
- import com.example.springsecurity.Entity.User;
- import com.example.springsecurity.Entity.UserRegister;
- import com.example.springsecurity.Repository.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.security.crypto.bcrypt.BCryptPasswordEncoder;
- import org.springframework.stereotype.Service;
- import java.util.List;
- @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.getUserRolesByUid(user.getId()));
- return user;
- }
- public String addUserByUsername(UserRegister userRegister){
- User newuser = userMapper.loadUserByUsername(userRegister.getUsername());
- if (newuser != null){
- return "账户存在,注册失败!";
- }else {
- //新用户密码采用BCryptPasswordEncoder(10)格式存入数据库
- userRegister.setPassword(new BCryptPasswordEncoder(10).encode(userRegister.getPassword()));
- //设置用户状态可用,没有锁定
- userRegister.setEnabled(true);
- userRegister.setLocked(false);
- //执行用户注册
- int adduser = userMapper.addUserByUsername(userRegister);
- //用户成功注册后,添加用户角色
- if(adduser > 0){
- User getuser =userMapper.loadUserByUsername(userRegister.getUsername());
- int addrole = userMapper.addRole(getuser.getId(),userRegister.getRole());
- if (addrole > 0){
- return "账户注册成功,角色注册成功!";
- }else{
- return "账户注册成功!角色注册失败!";
- }
- }else {
- return "账户注册失败!";
- }
- }
- }
- public List<Role> getAllRole(){
- return userMapper.getAllRole();
- }
- }

登录接口包含:
registerController用户注册接口
doRegisterController执行用户注册接口及返回注册结果
HelloController登录接口
- package com.example.springsecurity.Controller;
- import com.example.springsecurity.Service.UserService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.servlet.ModelAndView;
- @Controller
- public class registerController {
- @Autowired
- UserService userService;
- @GetMapping("/register")
- //registerController用户注册接口,将所有角色信息数据库取值并绑定roles赋给前端registerPage.html
- public ModelAndView resgister(){
- ModelAndView mv = new ModelAndView();
- mv.addObject("roles",userService.getAllRole());
- mv.setViewName("registerPage");
- return mv;
- }
- }

- package com.example.springsecurity.Controller;
- import com.example.springsecurity.Entity.UserRegister;
- import com.example.springsecurity.Service.UserService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RestController;
- @RestController
- public class doRegisterController {
- @Autowired
- UserService userService;
- @PostMapping("/doregister")
- //doRegisterController执行用户注册接口及返回注册结果
- public String doregister(UserRegister userRegister){
- return userService.addUserByUsername(userRegister);
- }
- }

- package com.example.springsecurity.Controller;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RestController;
- @RestController
- //HelloController登录接口,URL访问权限控制,分别对应不同的角色方能访问
- public class HelloController {
- @GetMapping("/admin/hello")
- public String admin(){
- return "hello admin";
- }
- @GetMapping("/user/hello")
- public String user(){
- return "hello user";
- }
- @GetMapping("/db/hello")
- public String dba(){
- return "hello dba";
- }
- @GetMapping("/hello")
- public String hello(){
- return "hello";
- }
- }

①注入用户服务类用于登录验证。
②配置用户登录密码需要BCryptPasswordEncoder(10)密文认证。
③对可访问资源URL限定固定的角色方能访问。
④用户注册接口和执行用户注册接口允许访问。
⑤成功登陆后跳转hello接口。
- package com.example.springsecurity.Config;
- import com.example.springsecurity.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.core.Authentication;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
- import org.springframework.security.crypto.password.PasswordEncoder;
- import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
- @Configuration
- public class WebSecurityLoginConfig extends WebSecurityConfigurerAdapter {
- //注入用户服务
- @Autowired
- UserService userService;
- //配置用户登录密码需要BCryptPasswordEncoder密文认证
- @Bean
- PasswordEncoder passwordEncoder(){
- return new BCryptPasswordEncoder(10);
- }
- //基于数据库的用户账号密码、角色、过期、锁定等认证
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception{
- auth.userDetailsService(userService);
- }
- @Override
- protected void configure(HttpSecurity httpSecurity) throws Exception {
- httpSecurity.authorizeRequests()
- //对可访问URL资源进行角色控制
- .antMatchers("/admin/**")
- .hasRole("admin")
- .antMatchers("/user/**")
- .access("hasAnyRole('admin','user')")
- .antMatchers("/db/**")
- .access("hasRole('dba') and hasRole('admin')")
- //用户注册接口和执行用户注册接口允许访问
- .antMatchers("/register","/doregister")
- .permitAll()
- //用户访问其他URL资源都必须认证后访问,即登陆后访问
- .anyRequest()
- .authenticated()
- //开启表单登录,即登录界面,登录URL为/login,登录参数用户名username密码password
- //Ajax或移动端通过POST请求登录,接口为/login,permitAll表示登录不需要认证即可访问
- .and()
- .formLogin()
- .loginProcessingUrl("/login")
- .permitAll()
- //成功登录后跳转到hello页面
- .successHandler(new AuthenticationSuccessHandler() {
- @Override
- public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
- response.setContentType("application/json;charset=utf-8");
- response.sendRedirect("/hello");
- }
- })
- .and()
- .csrf()
- .disable();
- }
- }

输入用户注册接口http://localhost:8080/register,自动跳转到registerPage.html,并将所有角色信息从数据库取出赋值给前端。
提交注册,跳转到http://localhost:8080/doregister接口,返回注册结果。
数据库中user表已经新增ceshi用户。
用户角色表user_role中新增数据:ceshi用户(uid:15)对应用户角色(rid:3)。
我们输入登录网址http://localhost:8080/login或者任意输入后缀地址,均可以访问登录接口。
用ceshi用户登陆后,具有用户角色,可以访问/user/hello接口或者hello接口,当然系统会自动跳转到hello接口页面。
当我们访问管理员接口/admin/hello接口,系统会因为缺少权限而拒绝访问Forbidden。
SpringSecurity可以非常轻松的实现用户登录验证、注册、跳转、URL接口访问控制等。
Thymeleaf可以将后端数据赋值给前端,便于前端使用,非常适合做登录网页前端设计。
Mybatis持久层非常灵活,可以实现用户自助注册、角色赋值、用户查询、角色查询等各种方法并于数据库交互,实现存储加密。
通过以上技术,我们就可以轻松打造简单安全的注册登录页面了,而不去纠结于各项安全设置和各种接口的设计。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。