赞
踩
Spring Security 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架 Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。
一般来说中大型的项目都是使用SpringSecurity 来做安全框架。小项目有Shiro的比较多,因为相比与SpringSecurity,Shiro的上手更加的简单。
一般Web应用的主要进行 认证 和 授权。
认证:验证当前访问系统的是不是本系统的用户,并且要确认具体是哪个用户。
授权:经过认证后判断当前用户是否有权限进行某个操作。
而认证和授权也是 SpringSecurity 作为安全框架的核心功能。
登录流程:
先进行登录,登录后带着生成的token进行访问,再给予对相应的权限进行操作。
- 在使用Spring Security构建的Web应用程序中,登录流程涉及多个关键组件,下面详细介绍这些组件及其在登录过程中扮演的角色:
-
- 1. Filter Chain(过滤器链)
- SecurityContextPersistenceFilter:维护安全上下文,确保线程间的安全信息传递。
-
- UsernamePasswordAuthenticationFilter:负责处理基于表单的登录请求,收集用户名和密码,调用AuthenticationManager进行验证。
-
- ConcurrentSessionFilter:管理并发会话,避免同一账号多处登录。
-
- ExceptionTranslationFilter:捕获并处理认证或授权失败的异常。
-
- FilterSecurityInterceptor:执行访问决策,依据用户权限判断是否允许访问特定资源。
-
- 2. AuthenticationManager(认证管理器)
- 负责处理认证请求,它接受一个Authentication对象(包含用户凭证),并返回一个经过完全填充的(已验证的或未经验证的)Authentication对象。对于基于用户名和密码的登录,Spring Security提供了DaoAuthenticationProvider,它使用UserDetailsService来检索用户信息。
-
- 3. UserDetailsService(用户详情服务)
- 接口定义了一个方法loadUserByUsername(String username),用于根据用户名加载用户信息。开发者需要实现这个接口,通常从数据库中查询用户信息。返回的是UserDetails对象,它包含用户的用户名、密码(通常是加密的)、权限等安全相关信息。
-
- 4. UserDetails(用户详情)
- 表示用户安全信息的核心接口,包含用户名、密码、账号是否过期、凭证是否过期、账号是否锁定以及赋予用户的权限集合。一个典型的实现是org.springframework.security.core.userdetails.User。
-
- 登录流程步骤(结合Spring Security组件):
- 请求登录页面:用户访问登录页面,该页面由Spring Security默认或自定义的登录页面处理。
-
- 提交登录信息:用户提交用户名和密码,这些信息通过UsernamePasswordAuthenticationFilter被封装成一个UsernamePasswordAuthenticationToken,并转发给AuthenticationManager。
-
- 验证用户凭证:
-
- AuthenticationManager委托给配置的AuthenticationProvider(如DaoAuthenticationProvider)处理。
-
- DaoAuthenticationProvider调用实现UserDetailsService的服务来加载用户详情(UserDetails)。
-
- 使用PasswordEncoder比较提交的密码与数据库中存储的密码哈希值,验证密码是否正确。
-
- 认证成功:
-
- 如果验证成功,AuthenticationProvider返回一个完全填充的Authentication对象,其中包含用户的角色和权限信息。
-
- AuthenticationManager将此认证对象设置到安全上下文中,使得后续请求能够访问用户信息和权限。
-
- 通常会生成一个会话或JWT,并将其发送给客户端,用于后续请求的认证。
-
- 认证失败:
-
- 认证失败时,抛出异常,由ExceptionTranslationFilter捕获并处理,可能重定向到登录页面显示错误消息,或响应HTTP 401 Unauthorized。
-
- 访问控制:
-
- 用户携带令牌访问受保护资源时,FilterSecurityInterceptor基于用户的角色和权限进行访问决策,决定是否允许访问。
-
- 如上:Spring Security提供了一个强大且灵活的安全认证与授权框架,确保了登录过程的严谨性和安全性。
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.xinzhi</groupId>
- <artifactId>SpringSecurityDemo2</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>SpringSecurityDemo2</name>
- <description>SpringSecurityDemo2</description>
- <properties>
- <java.version>11</java.version>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <spring-boot.version>2.6.2</spring-boot.version>
- </properties>
- <dependencies>
- <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>
-
- <!-- mysql驱动 -->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>8.0.33</version>
- </dependency>
-
- <!-- 连接池 -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>1.1.16</version>
- </dependency>
-
- <!-- mybatis -->
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>2.0.1</version>
- </dependency>
-
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <optional>true</optional>
- </dependency>
- <!--mybatis-plus的springboot支持-->
- <dependency>
- <groupId>com.baomidou</groupId>
- <artifactId>mybatis-plus-boot-starter</artifactId>
- <version>3.1.1</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-thymeleaf</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.github.penggle</groupId>
- <artifactId>kaptcha</artifactId>
- <version>2.3.2</version>
- <exclusions>
- <exclusion>
- <artifactId>javax.servlet-api</artifactId>
- <groupId>javax.servlet</groupId>
- </exclusion>
- </exclusions>
- </dependency>
-
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt</artifactId>
- <version>0.9.0</version>
- </dependency>
-
- <dependency>
- <groupId>javax.xml.bind</groupId>
- <artifactId>jaxb-api</artifactId>
- <version>2.3.1</version>
- </dependency>
-
- <dependency>
- <groupId>org.aspectj</groupId>
- <artifactId>aspectjweaver</artifactId>
- <version>1.8.13</version>
- </dependency>
- </dependencies>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-dependencies</artifactId>
- <version>${spring-boot.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.8.1</version>
- <configuration>
- <source>11</source>
- <target>11</target>
- <encoding>UTF-8</encoding>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
- </project>
- # ????
- spring.application.name=SpringSecurityDemo
-
- # ???
- server.port=8081
-
- #-----------------------------Mysql??
- spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
- spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
- #mybatis.config-location=classpath:mybatis-config.xml
- mybatis-plus.type-aliases-package=com.xinzhi.model
- mybatis-plus.mapper-locations=classpath:mapper/*.xml
- mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
- mybatis-plus.configuration.map-underscore-to-camel-case=true
-
-
- #-----------------------------Mysql
- spring.datasource.url=jdbc:mysql://localhost:3306/jdb?useUnicode=true&characterEncoding=utf-8&useSSL=false
- spring.datasource.username=root
- spring.datasource.password=123456
-
- server.servlet.session.timeout=1m
- SET NAMES utf8mb4;
- SET FOREIGN_KEY_CHECKS = 0;
-
- -- ----------------------------
- -- Table structure for menu
- -- ----------------------------
- DROP TABLE IF EXISTS `menu`;
- CREATE TABLE `menu` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `pattern` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
- PRIMARY KEY (`id`) USING BTREE
- ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;
-
- -- ----------------------------
- -- Records of menu
- -- ----------------------------
- INSERT INTO `menu` VALUES (1, '/admin/**');
- INSERT INTO `menu` VALUES (2, '/user/**');
- INSERT INTO `menu` VALUES (3, '/guest/**');
-
- -- ----------------------------
- -- Table structure for menu_role
- -- ----------------------------
- DROP TABLE IF EXISTS `menu_role`;
- CREATE TABLE `menu_role` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `rid` int(11) NULL DEFAULT NULL,
- `mid` int(11) NULL DEFAULT NULL,
- PRIMARY KEY (`id`) USING BTREE
- ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;
-
- -- ----------------------------
- -- Records of menu_role
- -- ----------------------------
- INSERT INTO `menu_role` VALUES (1, 1, 1);
- INSERT INTO `menu_role` VALUES (2, 1, 2);
- INSERT INTO `menu_role` VALUES (3, 2, 2);
- INSERT INTO `menu_role` VALUES (4, 3, 3);
-
- -- ----------------------------
- -- Table structure for role
- -- ----------------------------
- DROP TABLE IF EXISTS `role`;
- CREATE TABLE `role` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
- `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
- PRIMARY KEY (`id`) USING BTREE
- ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;
-
- -- ----------------------------
- -- Records of role
- -- ----------------------------
- INSERT INTO `role` VALUES (1, 'product', '商品管理员');
- INSERT INTO `role` VALUES (2, 'admin', '系统管理员');
- INSERT INTO `role` VALUES (3, 'user', '用户管理员');
-
- -- ----------------------------
- -- Table structure for user
- -- ----------------------------
- DROP TABLE IF EXISTS `user`;
- CREATE TABLE `user` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
- `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
- `enabled` tinyint(1) NULL DEFAULT NULL,
- `accountNonExpired` tinyint(1) NULL DEFAULT NULL,
- `accountNonLocked` tinyint(1) NULL DEFAULT NULL,
- `credentialsNonExpired` tinyint(1) NULL DEFAULT NULL,
- PRIMARY KEY (`id`) USING BTREE
- ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;
-
- -- ----------------------------
- -- Records of user
- -- ----------------------------
- INSERT INTO `user` VALUES (1, 'root', '$2a$10$YeilFczw8sQ1RBthIFLRW.pI/KkdbDofOmZ0w5Wfq9mMMyL3ylC/.', 1, 1, 1, 1);
- INSERT INTO `user` VALUES (2, 'admin', '$2a$10$YeilFczw8sQ1RBthIFLRW.pI/KkdbDofOmZ0w5Wfq9mMMyL3ylC/.', 1, 1, 1, 1);
- INSERT INTO `user` VALUES (3, 'han', '$2a$10$YeilFczw8sQ1RBthIFLRW.pI/KkdbDofOmZ0w5Wfq9mMMyL3ylC/.', 1, 1, 1, 1);
-
- -- ----------------------------
- -- Table structure for user_role
- -- ----------------------------
- DROP TABLE IF EXISTS `user_role`;
- CREATE TABLE `user_role` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `uid` int(11) NULL DEFAULT NULL,
- `rid` int(11) NULL DEFAULT NULL,
- PRIMARY KEY (`id`) USING BTREE
- ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;
-
- -- ----------------------------
- -- Records of user_role
- -- ----------------------------
- INSERT INTO `user_role` VALUES (1, 1, 1);
- INSERT INTO `user_role` VALUES (2, 1, 2);
- INSERT INTO `user_role` VALUES (3, 2, 2);
- INSERT INTO `user_role` VALUES (4, 3, 3);
-
- SET FOREIGN_KEY_CHECKS = 1;
实体类
权限表
package com.xinzhi.model;
import java.util.List;
/**
* 权限表
*/
public class Menu {
private Integer id;
private String pattern;
private List<Role> roles;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
}
result
package com.xinzhi.model;
import java.io.Serializable;
public class Result<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 成功标志
*/
private boolean success = true;
/**
* 返回处理消息
*/
private String message = "操作成功!";
/**
* 返回代码
*/
private Integer code = 0;
/**
* 返回数据对象 data
*/
private T result;
public static long getSerialVersionUID() {
return serialVersionUID;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
/**
* 时间戳
*/
private long timestamp = System.currentTimeMillis();
public Result() {
}
public Result<T> success(String message) {
this.message = message;
this.code = 200;
this.success = true;
return this;
}
public static Result<Object> ok() {
Result<Object> r = new Result<Object>();
r.setSuccess(true);
r.setCode(200);
r.setMessage("成功");
return r;
}
public static Result<Object> ok(String msg) {
Result<Object> r = new Result<Object>();
r.setSuccess(true);
r.setCode(200);
r.setMessage(msg);
return r;
}
public static Result<Object> ok(Object data) {
Result<Object> r = new Result<Object>();
r.setSuccess(true);
r.setCode(200);
r.setResult(data);
return r;
}
public static Result<Object> error(String msg) {
return error(500, msg);
}
public static Result<Object> error(int code, String msg) {
Result<Object> r = new Result<Object>();
r.setCode(code);
r.setMessage(msg);
r.setSuccess(false);
return r;
}
public Result<T> error500(String message) {
this.message = message;
this.code = 500;
this.success = false;
return this;
}
/**
* 无权限访问返回结果
*/
public static Result<Object> noauth(String msg) {
return error(555, msg);
}
}
角色信息表
package com.xinzhi.model;
/**
* 角色信息
*/
public class Role {
/**
* id
*/
private Integer id;
/**
* 角色名
*/
private String name;
/**
* 角色说明
*/
private String content;
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 == null ? null : name.trim();
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content == null ? null : content.trim();
}
}
用户信息表
package com.xinzhi.model;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
/**
* 用户信息
*/
public class User implements UserDetails {
private Integer id;
private String username; //用户名
private String password; //密码
private boolean accountNonExpired; //是否没过期
private boolean accountNonLocked; //是否没被锁定
private boolean credentialsNonExpired; //密码是否没过期
private boolean enabled; //账号是否可用
private Collection<? extends GrantedAuthority> authorities; //用户的权限集合
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public void setPassword(String password) {
this.password = password;
}
public void setUsername(String username) {
this.username = username;
}
public void setAccountNonExpired(boolean accountNonExpired) {
this.accountNonExpired = accountNonExpired;
}
public void setAccountNonLocked(boolean accountNonLocked) {
this.accountNonLocked = accountNonLocked;
}
public void setCredentialsNonExpired(boolean credentialsNonExpired) {
this.credentialsNonExpired = credentialsNonExpired;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = authorities;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true; //暂时未用到,直接返回true,表示账户未过期
}
@Override
public boolean isAccountNonLocked() {
return true; //暂时未用到,直接返回true,表示账户未被锁定
}
@Override
public boolean isCredentialsNonExpired() {
return true; //暂时未用到,直接返回true,表示账户密码未过期
}
@Override
public boolean isEnabled() {
return enabled;
}
}
dao接口
- package com.xinzhi.dao;
-
- import com.baomidou.mybatisplus.core.mapper.BaseMapper;
- import com.xinzhi.model.Menu;
- import com.xinzhi.model.Role;
- import com.xinzhi.model.User;
- import org.apache.ibatis.annotations.Mapper;
- import org.apache.ibatis.annotations.Param;
-
- import java.util.List;
-
- @Mapper
- public interface UserMapper extends BaseMapper<User> {
-
- User selectByUsername(String username);
-
- List<Role> selectRolesByUserId(Integer id);
-
- Integer updatePassword(@Param("username") String username, @Param("password") String password);
-
- List<Menu> selectMenuByRoleIds(@Param("roleIds")List<Integer> roleIds);
-
- }
usermapper
- <?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.xinzhi.dao.UserMapper" >
-
- <sql id="Base_Column_List" >
- id, username, password, enabled, accountNonExpired, accountNonLocked, credentialsNonExpired
- </sql>
- <update id="updatePassword">
- update user set password=#{password} where username=#{username}
- </update>
-
- <select id="selectByUsername" resultType="com.xinzhi.model.User">
- select
- <include refid="Base_Column_List" />
- from user
- where username = #{username}
- </select>
- <select id="selectRolesByUserId" resultType="com.xinzhi.model.Role">
- select
- r.name,r.id,r.content
- from
- role r
- left join
- user_role ur
- on r.id = ur.rid
- where ur.uid=#{uid}
- </select>
- <select id="selectMenuByRoleIds" resultType="com.xinzhi.model.Menu">
- select
- m.id,m.pattern
- from menu m
- left join menu_role rm on m.id=rm.mid
- where
- <foreach collection="roleIds" open="rm.rid in(" item="id" close=")" separator=",">
- #{id}
- </foreach>
- </select>
-
- </mapper>
- package com.xinzhi.service;
-
- import com.xinzhi.dao.UserMapper;
- import com.xinzhi.model.Menu;
- import com.xinzhi.model.Role;
- import com.xinzhi.model.User;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.core.authority.AuthorityUtils;
- 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.util.Collections;
- import java.util.List;
- import java.util.stream.Collectors;
-
- /**
- * 权限
- */
- @Service
- @Slf4j
-
- public class SpringUserDetailsService implements UserDetailsService {
-
- @Autowired
- private UserMapper userMapper;
-
-
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- User user = userMapper.selectByUsername(username);
- // 判断用户是否存在
- if (user == null){
- throw new UsernameNotFoundException("用户不存在");
- }
- // 根据用户ID查找用户的角色列表
- List<Role> roles = userMapper.selectRolesByUserId(user.getId());
- // 获取角色ID列表
- List<Integer> roleIds = roles.stream().map(s -> s.getId()).collect(Collectors.toList());
- // 根据角色ID列表查找权限
- List<Menu> menus = userMapper.selectMenuByRoleIds(roleIds);
- // 获取角色名称列表并加上前缀 "ROLE_"
- List<String> collect = roles.stream().map(s -> "ROLE_" + s.getName()).collect(Collectors.toList());
- // 获取菜单权限模式
- List<String> collect1 = menus.stream().map(m -> m.getPattern()).collect(Collectors.toList());
- // 合并菜单权限和角色权限
- Collections.addAll(collect1,collect.stream().toArray(String[] ::new));
- // 将权限列表设置到用户对象中
- user.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList(String.join(",",collect1)));
- // 返回包含用户详情的User对象
- return user;
-
- }
- }
config配置类
- package com.xinzhi.config;
-
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.xinzhi.filter.CaptchaCodeFilter;
- import com.xinzhi.service.SpringUserDetailsService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.security.authentication.AuthenticationManager;
- import org.springframework.security.authorization.AuthorizationDecision;
- import org.springframework.security.config.BeanIds;
- 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.config.http.SessionCreationPolicy;
- import org.springframework.security.core.GrantedAuthority;
- import org.springframework.security.core.authority.SimpleGrantedAuthority;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
- import org.springframework.security.crypto.password.PasswordEncoder;
- import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
- import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
- import org.springframework.web.cors.CorsConfiguration;
- import org.springframework.web.cors.CorsConfigurationSource;
-
- import javax.annotation.Resource;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.HashMap;
-
- @Configuration
- public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
- @Autowired
- private CaptchaCodeFilter captchaCodeFilter;
-
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- // 表单认证
- http.formLogin()
- .loginProcessingUrl("/login")
- // .successForwardUrl("/index")
- // .failureForwardUrl("/fail") //登录失败跳转地址
- //认证成功处理
- .successHandler(((request, response, authentication) -> {
- HashMap<String, Object> map = new HashMap<>();
- map.put("msg", "认证成功");
- map.put("status", 200);
- map.put("用户信息", authentication.getPrincipal());
- response.setContentType("application/json;charset=UTF-8");
- String s = new ObjectMapper().writeValueAsString(map);
- response.getWriter().println(s);
- }))
- // 认证失败处理
- .failureHandler(((request, response, exception) -> {
- HashMap<String, Object> map = new HashMap<>();
- map.put("msg", "认证失败");
- map.put("status", 500);
- map.put("异常信息", exception.getMessage());
- response.setContentType("application/json;charset=UTF-8");
- String s = new ObjectMapper().writeValueAsString(map);
- response.getWriter().println(s);
- }))
- .loginPage("/login.html");
-
- // 拦截
- http.authorizeHttpRequests()
- .antMatchers("/login.html", "/kaptcha", "/authentication", "/refreshtoken").permitAll()
- .antMatchers("/fail.html").permitAll() //fail.html 不需要被认证
- .antMatchers("/invalidSession.html").permitAll()
- .anyRequest().access((authenticationSupplier, requestAuthorizationContext) -> {
- Collection<? extends GrantedAuthority> authorities = authenticationSupplier.get().getAuthorities();
- String requestURI = requestAuthorizationContext.getRequest().getRequestURI();
- SimpleGrantedAuthority simpleGrantedAuthority
- = new SimpleGrantedAuthority(requestURI);
- boolean contains = authorities.contains(simpleGrantedAuthority);
- return new AuthorizationDecision(contains);
- });
- // .antMatchers("/user/detail").hasAuthority("/user/**")
- // .antMatchers("/index.html").hasRole("super")
- // .anyRequest().authenticated();
-
- // 异常处理
- http.exceptionHandling()
- .accessDeniedHandler(((request, response, accessDeniedException) -> {
- HashMap<String, Object> map = new HashMap<>();
- map.put("msg", "禁止访问");
- map.put("status", 403);
- map.put("异常信息", accessDeniedException.getMessage());
- response.setContentType("application/json;charset=UTF-8");
- String s = new ObjectMapper().writeValueAsString(map);
- response.getWriter().println(s);
- }));
- // session管理
- http.sessionManagement()
- .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
- //.invalidSessionUrl("/invalidSession.html") //非法超时session跳转页面
- .maximumSessions(1) // 允许登录的最多用户数量
- .maxSessionsPreventsLogin(false) // true表示已经登录就不予许再次登录, false表示允许再次登录但是之前的登录账户会被踢下线
- .expiredSessionStrategy(new CustomExpiredSessionStrategy());
-
- /**
- * 退出登录
- */
- http.logout().logoutSuccessHandler(((request, response, authentication) -> {
- HashMap<String, Object> map = new HashMap<>();
- map.put("msg", "退出成功");
- map.put("status", 200);
- response.setContentType("application/json;charset=UTF-8");
- String s = new ObjectMapper().writeValueAsString(map);
- response.getWriter().println(s);
- }));
- // 验证码
- http.addFilterBefore(captchaCodeFilter, UsernamePasswordAuthenticationFilter.class);
- //
- /**
- * 记住我
- */
- http.rememberMe().tokenValiditySeconds(7 * 24 * 3600);
- //跨域
- http.csrf().disable();
- // 跨域
- // http.cors(c -> {
- // CorsConfigurationSource source = request -> {
- // CorsConfiguration config = new CorsConfiguration();
- // config.setAllowedOrigins(Arrays.asList("*"));
- // config.setAllowedMethods(Arrays.asList("*"));
- // config.addAllowedHeader("*");
- // return config;
- // };
- // c.configurationSource(source);
- // });
- // CSRF 跨站攻击
- // http.csrf()
- // .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
- // .ignoringAntMatchers("/authentication");
- }
-
-
-
- /**
- * 注入加密类
- * @return
- */
- @Bean("passwordEncoder")
- public PasswordEncoder passwordEncoder(){
- return new BCryptPasswordEncoder();
- }
-
- @Resource
- private SpringUserDetailsService userDetailsService;
- @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
- @Override
- protected AuthenticationManager authenticationManager() throws Exception {
- return super.authenticationManager();
- }
-
- @Override
- protected void configure(AuthenticationManagerBuilder builder) throws Exception {
- // 加密方式认证
- builder.userDetailsService(userDetailsService)
- .passwordEncoder(passwordEncoder());
- }
-
- }
Controller层
- package com.xinzhi.controller;
-
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.ResponseBody;
-
-
- @Controller
- @RequestMapping("/user")
- public class TestController {
-
- @RequestMapping("/hello")
- @ResponseBody
- public String test(){
- return "security";
- }
-
-
- @RequestMapping("/index")
- public String index(){
- return "redirect:/index.html";
- }
-
- @PostMapping("/fail")
- public String fail(){
- return "redirect:/fail.html";
- }
-
- @GetMapping("/detail")
-
- public String detail(){
- return "detail";
- }
-
- @GetMapping("/add")
- @ResponseBody
- public String add(){
- return "add";
- }
-
- @GetMapping("/delete")
- @ResponseBody
- public String delete(){
- return "delete";
- }
-
-
- @GetMapping("/update")
- @ResponseBody
- public String update(){
- return "update";
- }
-
- @GetMapping("/select")
- @ResponseBody
- public String select(){
- return "select";
- }
-
-
- }
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>登录</title></head>
- <body>
- <!--不想要jwt是把authentication换成login就是普通的了-->
- <form action="/authentication" method="post">
- 用户名:<input type="text" name="username"/> <br>
- 密码: <input type="password" name="password"/> <br>
- 验证码:<input type="text" name="captchaCode"/><img src="/kaptcha" id="kaptcha" width="110px" height="40px"/> <br>
- <input type="checkbox" name="remember-me" value="on"/>记住密码 <br>
- <input type="submit" value="提交"/>
- </form>
- <script>
- window.onload=function(){
- var kaptchaImg = document.getElementById("kaptcha");
- kaptchaImg.onclick = function(){
- kaptchaImg.src = "/kaptcha?" + Math.floor(Math.random() * 100)
- }
- }
- </script>
- </body>
- </html>
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <a href="/logout" >退出</a>
- 详情页
- </body>
- </html>
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>error</title>
- </head>
- <body>
- 操作失败,请重新登录. <a href="/login.html">跳转</a>
- </body>
- </html>
index.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- 首页
- </body>
- </html>
http://localhost:8080/login.html
在配置类里有相对应的配置类就可已了直接用就好了
在login页面里也有先对应的代码直接用就好了
退出页面有相对应的代码
配置文件也有对应的代码
pom有对应的依赖了他的依赖是
- <dependency>
- <groupId>com.github.penggle</groupId>
- <artifactId>kaptcha</artifactId>
- <version>2.3.2</version>
- <exclusions>
- <exclusion>
- <artifactId>javax.servlet-api</artifactId>
- <groupId>javax.servlet</groupId>
- </exclusion>
- </exclusions>
- </dependency>
创建一个vo
- package com.xinzhi.model.vo;
-
- import lombok.Data;
-
- import java.time.LocalDateTime;
-
- /**
- * 验证码的实体类
- */
- @Data
- public class CaptchaImageVO {
-
- //验证码文字
- private String code;
- //验证码失效时间
- private LocalDateTime expireTime;
-
- public CaptchaImageVO(String code, int expireAfterSeconds){
- this.code = code;
- this.expireTime = LocalDateTime.now().plusSeconds(expireAfterSeconds);
- }
-
- //验证码是否失效
- public boolean isExpried() {
- return LocalDateTime.now().isAfter(expireTime);
- }
-
- public String getCode() {
- return code;
- }
- }
- #????????
- kaptcha.border=no
- kaptcha.border.color=105,179,90
- kaptcha.image.width=100
- kaptcha.image.height=45
- kaptcha.session.key=code
- kaptcha.textproducer.font.color=blue
- kaptcha.textproducer.font.size=35
- kaptcha.textproducer.char.length=4
- kaptcha.textproducer.font.names=??,??,????
- package com.xinzhi.config;
-
- import com.google.code.kaptcha.impl.DefaultKaptcha;
- import com.google.code.kaptcha.util.Config;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.PropertySource;
- import org.springframework.stereotype.Component;
-
- import java.util.Properties;
- //验证码的配置文件
- @Component
- @PropertySource(value = {"classpath:kaptcha.properties"})
- public class CaptchaConfig {
-
- @Value("${kaptcha.border}")
- private String border;
- @Value("${kaptcha.border.color}")
- private String borderColor;
- @Value("${kaptcha.textproducer.font.color}")
- private String fontColor;
- @Value("${kaptcha.image.width}")
- private String imageWidth;
- @Value("${kaptcha.image.height}")
- private String imageHeight;
- @Value("${kaptcha.textproducer.char.length}")
- private String charLength;
- @Value("${kaptcha.textproducer.font.names}")
- private String fontNames;
- @Value("${kaptcha.textproducer.font.size}")
- private String fontSize;
- @Value("${kaptcha.session.key}")
- private String sessionKey;
-
- @Bean(name = "captchaProducer")
- public DefaultKaptcha getKaptchaBean() {
- DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
- Properties properties = new Properties();
- properties.setProperty("kaptcha.border", border);
- properties.setProperty("kaptcha.border.color", borderColor);
- properties.setProperty("kaptcha.textproducer.font.color", fontColor);
- properties.setProperty("kaptcha.image.width", imageWidth);
- properties.setProperty("kaptcha.image.height", imageHeight);
- properties.setProperty("kaptcha.session.key", sessionKey);
- properties.setProperty("kaptcha.textproducer.char.length", charLength);
- properties.setProperty("kaptcha.textproducer.font.names", fontNames);
- properties.setProperty("kaptcha.textproducer.font.size",fontSize);
- Config config = new Config(properties);
- defaultKaptcha.setConfig(config);
- return defaultKaptcha;
- }
-
- }
-
-
- package com.xinzhi.controller;
-
- import com.google.code.kaptcha.impl.DefaultKaptcha;
- import com.xinzhi.model.vo.CaptchaImageVO;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.RestController;
-
- import javax.annotation.Resource;
- import javax.imageio.ImageIO;
- import javax.servlet.ServletOutputStream;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- import java.awt.image.BufferedImage;
-
- /**
- * 获取验证码
- */
- @RestController
- public class CaptchaController extends Throwable {
-
- @Resource
- DefaultKaptcha captchaProducer;
- /**
- * 获取验证码
- */
- @RequestMapping(value = "/kaptcha", method = RequestMethod.GET)
- public void kaptcha(HttpSession session, HttpServletResponse response) throws Exception {
-
- response.setDateHeader("Expires", 0);
- response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
- response.addHeader("Cache-Control", "post-check=0, pre-check=0");
- response.setHeader("Pragma", "no-cache");
- response.setContentType("image/jpeg");
-
- String capText = captchaProducer.createText();
- System.out.println(capText);
- CaptchaImageVO captchaImageVO = new CaptchaImageVO(capText,2 * 60);
- //将验证码存到session
- session.setAttribute("code", capText);
- //将图片返回给前端
- try(ServletOutputStream out = response.getOutputStream();) {
- BufferedImage bi = captchaProducer.createImage(capText);
- ImageIO.write(bi, "jpg", out);
- out.flush();
- }//使用try-with-resources不用手动关闭流
- }
- }
-
-
-
-
- package com.xinzhi.filter;
-
- import com.alibaba.druid.util.StringUtils;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import org.springframework.stereotype.Component;
- import org.springframework.web.bind.ServletRequestBindingException;
- import org.springframework.web.bind.ServletRequestUtils;
- import org.springframework.web.context.request.ServletWebRequest;
- import org.springframework.web.filter.OncePerRequestFilter;
-
- import javax.servlet.FilterChain;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- import java.io.IOException;
- import java.util.HashMap;
-
- /**
- * 验证码
- */
- @Component
- public class CaptchaCodeFilter extends OncePerRequestFilter {
-
- @Override
- protected void doFilterInternal(HttpServletRequest request,
- HttpServletResponse response,
- FilterChain filterChain)
- throws ServletException, IOException {
- // 必须是登录的post请求才能进行验证,其他的直接放行
- if(StringUtils.equals("/login",request.getRequestURI())
- && StringUtils.equalsIgnoreCase(request.getMethod(),"post")){
-
- //1.验证谜底与用户输入是否匹配
- if (!validate(new ServletWebRequest(request), response)){
- return;
- }
- }
- //通过校验,就放行
- filterChain.doFilter(request,response);
-
- }
-
- private Boolean validate(ServletWebRequest request,HttpServletResponse response) throws ServletRequestBindingException, IOException {
-
- HttpSession session = request.getRequest().getSession();
- //获取用户登录界面输入的captchaCode
- String codeInRequest = ServletRequestUtils.getStringParameter(
- request.getRequest(),"captchaCode");
- if(StringUtils.isEmpty(codeInRequest)){
- HashMap<String, Object> map = new HashMap<>();
- map.put("msg", "验证码不能为空");
- map.put("status", 500);
- response.setContentType("application/json;charset=UTF-8");
- String s = new ObjectMapper().writeValueAsString(map);
- response.getWriter().println(s);
- return false;
- }
-
- // 获取session池中的验证码谜底
- String codeInSession = (String)
- session.getAttribute("code");
- // 请求验证码校验
- if(!StringUtils.equals(codeInSession, codeInRequest)) {
- HashMap<String, Object> map = new HashMap<>();
- map.put("msg", "验证码不匹配");
- map.put("status", 500);
- response.setContentType("application/json;charset=UTF-8");
- String s = new ObjectMapper().writeValueAsString(map);
- response.getWriter().println(s);
- return false;
- }
- return true;
- }
- }
.antMatchers("/login.html", "/fail.html", "/invalidSession.html","/kaptcha").permitAll()
也有这段代码
引入依赖 不用管也有配置类里
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt</artifactId>
- <version>0.9.0</version>
- </dependency>
工具类
- package com.xinzhi.utils;
-
- import io.jsonwebtoken.Claims;
- import io.jsonwebtoken.Jwts;
- import io.jsonwebtoken.SignatureAlgorithm;
- import lombok.Data;
- import org.springframework.security.core.userdetails.UserDetails;
- import org.springframework.stereotype.Component;
-
- import java.util.Date;
- import java.util.HashMap;
- import java.util.Map;
-
- @Data
- @Component
- public class JwtTokenUtil {
- private String secret="xinzhi";
- private Long expiration=3600000L;
- private String header="JWTHeaderName";
-
-
- /**
- * 生成token令牌
- *
- * @param userDetails 用户
- * @return 令token牌
- */
- public String generateToken(UserDetails userDetails) {
- Map<String, Object> claims = new HashMap<>(2);
- //获取用户名
- claims.put("sub", userDetails.getUsername());
- // 创建时间
- claims.put("created", new Date());
- return generateToken(claims);
- }
-
- /**
- * 从令牌中获取用户名
- *
- * @param token 令牌
- * @return 用户名
- */
- public String getUsernameFromToken(String token) {
- String username;
- try {
- Claims claims = getClaimsFromToken(token);
- username = claims.getSubject();
- } catch (Exception e) {
- username = null;
- }
- return username;
- }
-
- /**
- * 判断令牌是否过期
- *
- * @param token 令牌
- * @return 是否过期
- */
- public Boolean isTokenExpired(String token) {
- try {
- Claims claims = getClaimsFromToken(token);
- Date expiration = claims.getExpiration();
- return expiration.before(new Date());
- } catch (Exception e) {
- return false;
- }
- }
-
- /**
- * 刷新令牌
- *
- * @param token 原令牌
- * @return 新令牌
- */
- public String refreshToken(String token) {
- String refreshedToken;
- try {
- Claims claims = getClaimsFromToken(token);
- claims.put("created", new Date());
- refreshedToken = generateToken(claims);
- } catch (Exception e) {
- refreshedToken = null;
- }
- return refreshedToken;
- }
-
- /**
- * 验证令牌
- *
- * @param token 令牌
- * @param userDetails 用户
- * @return 是否有效
- */
- public Boolean validateToken(String token, UserDetails userDetails) {
- String username = getUsernameFromToken(token);
- return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
- }
-
-
- /**
- * 从claims生成令牌
- *
- * @param claims 数据声明
- * @return 令牌
- */
- private String generateToken(Map<String, Object> claims) {
- Date expirationDate = new Date(System.currentTimeMillis() + expiration);
- return Jwts.builder().setClaims(claims)
- .setExpiration(expirationDate)
- .signWith(SignatureAlgorithm.HS512, secret)
- .compact();
- }
-
- /**
- * 从令牌中获取数据声明
- *
- * @param token 令牌
- * @return 数据声明
- */
- private Claims getClaimsFromToken(String token) {
- Claims claims;
- try {
- claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
- } catch (Exception e) {
- claims = null;
- }
- return claims;
- }
-
- }
- package com.xinzhi.exception;
-
- /**
- * jwt异常
- */
-
- public class CustomException extends RuntimeException {
- //异常错误编码
- private int code ;
- //异常信息
- private String message;
-
- private CustomException(){}
-
- public CustomException(int code, String message) {
- this.code = code;
- this.message = message;
- }
-
- public int getCode() {
- return code;
- }
-
- @Override
- public String getMessage() {
- return message;
- }
- }
- package com.xinzhi.service;
-
- import com.xinzhi.exception.CustomException;
- import com.xinzhi.utils.JwtTokenUtil;
- import org.springframework.security.authentication.AuthenticationManager;
- import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
- import org.springframework.security.core.Authentication;
- import org.springframework.security.core.AuthenticationException;
- import org.springframework.security.core.context.SecurityContextHolder;
- import org.springframework.security.core.userdetails.UserDetails;
- import org.springframework.security.core.userdetails.UserDetailsService;
- import org.springframework.stereotype.Service;
-
- import javax.annotation.Resource;
-
- @Service
- public class JwtAuthService {
-
- @Resource
- private AuthenticationManager authenticationManager;
- @Resource
- private UserDetailsService userDetailsService;
- @Resource
- private JwtTokenUtil jwtTokenUtil;
-
- public UserDetails login(String username, String password) throws CustomException {
- try{
-
- // 通过手机号查到用户信息
-
- //使用用户名密码进行登录验证
- UsernamePasswordAuthenticationToken upToken =
- new UsernamePasswordAuthenticationToken(username, password);
- Authentication authentication = authenticationManager.authenticate(upToken);
- SecurityContextHolder.getContext().setAuthentication(authentication);
- }catch(AuthenticationException e){
- throw new CustomException(500, "用户名或密码不正确");
- }
-
- //返回了一个用户信息
- UserDetails userDetails = userDetailsService.loadUserByUsername( username );
- return userDetails;
-
- }
-
- public String refreshToken(String oldToken) {
- if (!jwtTokenUtil.isTokenExpired(oldToken)) {
- return jwtTokenUtil.refreshToken(oldToken);
- }
- return null;
- }
- }
Controller
- package com.xinzhi.controller;
-
- import com.google.code.kaptcha.impl.DefaultKaptcha;
- import com.xinzhi.model.vo.CaptchaImageVO;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.RestController;
-
- import javax.annotation.Resource;
- import javax.imageio.ImageIO;
- import javax.servlet.ServletOutputStream;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- import java.awt.image.BufferedImage;
-
- /**
- * 获取验证码
- */
- @RestController
- public class CaptchaController extends Throwable {
-
- @Resource
- DefaultKaptcha captchaProducer;
- /**
- * 获取验证码
- */
- @RequestMapping(value = "/kaptcha", method = RequestMethod.GET)
- public void kaptcha(HttpSession session, HttpServletResponse response) throws Exception {
-
- response.setDateHeader("Expires", 0);
- response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
- response.addHeader("Cache-Control", "post-check=0, pre-check=0");
- response.setHeader("Pragma", "no-cache");
- response.setContentType("image/jpeg");
-
- String capText = captchaProducer.createText();
- System.out.println(capText);
- CaptchaImageVO captchaImageVO = new CaptchaImageVO(capText,2 * 60);
- //将验证码存到session
- session.setAttribute("code", capText);
- //将图片返回给前端
- try(ServletOutputStream out = response.getOutputStream();) {
- BufferedImage bi = captchaProducer.createImage(capText);
- ImageIO.write(bi, "jpg", out);
- out.flush();
- }//使用try-with-resources不用手动关闭流
- }
- }
- package com.xinzhi.filter;
-
-
- import com.xinzhi.service.SpringUserDetailsService;
- import com.xinzhi.utils.JwtTokenUtil;
- import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
- import org.springframework.security.core.Authentication;
- import org.springframework.security.core.context.SecurityContextHolder;
- import org.springframework.security.core.userdetails.UserDetails;
- import org.springframework.stereotype.Component;
- import org.springframework.util.StringUtils;
- import org.springframework.web.filter.OncePerRequestFilter;
-
- import javax.annotation.Resource;
- import javax.servlet.FilterChain;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
-
- /**
- * jwt
- */
- @Component
- public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
-
- @Resource
- private SpringUserDetailsService myUserDetailsService;
-
- @Resource
- private JwtTokenUtil jwtTokenUtil;
-
- @Override
- protected void doFilterInternal(HttpServletRequest request,
- HttpServletResponse response,
- FilterChain filterChain)
- throws ServletException, IOException {
- String jwtToken = request.getHeader(jwtTokenUtil.getHeader());
- if(!StringUtils.isEmpty(jwtToken)){
- String username = jwtTokenUtil.getUsernameFromToken(jwtToken);
- Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
- //如果可以正确的从JWT中提取用户信息,并且该用户未被授权
- if(username != null){
- UserDetails userDetails = myUserDetailsService.loadUserByUsername(username);
- if(jwtTokenUtil.validateToken(jwtToken,userDetails)){
- //给使用该JWT令牌的用户进行授权
- UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails,null, userDetails.getAuthorities());
- SecurityContextHolder.getContext().setAuthentication(authenticationToken);
- }
- }
- }
- filterChain.doFilter(request,response);
-
- }
- }
依赖 已经有了
- <dependency>
- <groupId>org.aspectj</groupId>
- <artifactId>aspectjweaver</artifactId>
- <version>1.8.13</version>
- </dependency>
代码
- package com.xinzhi.aspest;
-
- import com.xinzhi.model.User;
- import lombok.Data;
- import org.aspectj.lang.JoinPoint;
- import org.aspectj.lang.annotation.*;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.security.core.context.SecurityContextHolder;
- import org.springframework.stereotype.Component;
- import org.springframework.web.context.request.RequestContextHolder;
- import org.springframework.web.context.request.ServletRequestAttributes;
-
- import javax.servlet.http.HttpServletRequest;
- import java.util.Arrays;
-
- @Component("myAspect")
- @Aspect
- @Data
- public class MyAspect {
- // 打印日志
-
- private final static Logger logger= LoggerFactory.getLogger(MyAspect.class);
-
- //@Before指在切点方法之前执行,也就是在Controller层方法执行之前执行,这里可以通过JoinPoint获取一些有关方法的信息,在这里也可以修改参数的值
-
- //@Before()括号里设置的是切点方法的名称
- @Before("execution(public * com.xinzhi.controller..*.*(..))")
- public void doBefore(JoinPoint joinPoint) throws Throwable {
- // 接收到请求,记录请求内容
- ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
- HttpServletRequest request = attributes.getRequest();
- Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
- if(principal.equals("anonymousUser")){
- logger.info("匿名用户");
- return;
- }
- User user =(User)(principal);
- // 记录下请求内容
- logger.info("URL : " + request.getRequestURI().toString());
- logger.info("HTTP_METHOD : " + request.getMethod());
- logger.info("IP : " + request.getRemoteAddr());
- logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
- logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
- logger.info("用户 : " + user.getUsername());
- }
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。