Spring-Security實現(xiàn)登錄接口流程
簡介
Security
是 Spring
家族中的一個安全管理框架。相比與另外一個安全框架Shiro
,它提供了更豐富的功能,社區(qū)資源也比Shiro豐富。
具體介紹和入門看springSecurity入門
原理初探
在實現(xiàn)之前幺要了解一下登錄校驗的流程以及SpringSecurity
的原理以及認證流程
1、登錄校驗流程
2、 SpringSecurity完整流程
SpringSecurity
的原理其實就是一個過濾器鏈,內部包含了提供各種功能的過濾器。這里我們可以看看入門案例中的過濾器。
圖中只展示了核心過濾器,其它的非核心過濾器并沒有在圖中展示。
UsernamePasswordAuthenticationFilter:負責處理我們在登陸頁面填寫了用戶名密碼后的登陸請求。入門案例的認證工作主要有它負責。
ExceptionTranslationFilter:處理過濾器鏈中拋出的任何AccessDeniedException
和AuthenticationException
。
FilterSecurityInterceptor:負責權限校驗的過濾器。
我們可以通過Debug
查看當前系統(tǒng)中SpringSecurity
過濾器鏈中有哪些過濾器及它們的順序。
3、認證流程
概念速查:
Authentication
接口: 它的實現(xiàn)類,表示當前訪問系統(tǒng)的用戶,封裝了用戶相關信息。AuthenticationManager
接口:定義了認證Authentication的方法UserDetailsService
接口:加載用戶特定數(shù)據(jù)的核心接口。里面定義了一個根據(jù)用戶名查詢用戶信息的方法。UserDetails
接口:提供核心用戶信息。通過UserDetailsService
根據(jù)用戶名獲取處理的用戶信息要封裝成UserDetails
對象返回。然后將這些信息封裝到Authentication
對象中。
實現(xiàn)思路
登錄
? ①自定義登錄接口
? 調用ProviderManager
的方法進行認證 如果認證通過生成jwt
? 把用戶信息存入redis
中
? ②自定義UserDetailsService
? 在這個實現(xiàn)類中去查詢數(shù)據(jù)庫
校驗:
? ①定義Jwt認證過濾器
? 獲取token
? 解析token
獲取其中的userid
? 從redis
中獲取用戶信息
? 存入SecurityContextHolder
這里我們主要是實現(xiàn)登錄接口的功能
核心思想就是就是將認證流程
中的UserDetailsService
重寫其loadUserByUsername
的方法,使其從數(shù)據(jù)庫中查詢數(shù)據(jù),然后用自己的類(我這里是UserLogin
)實現(xiàn)UserDetails
,在loadUserByUsername
中返回UserLogin
登錄接口實現(xiàn)
準備工作
添加依賴,添加工具類,創(chuàng)建數(shù)據(jù)庫,編寫配置文件
1、添加依賴
<!--redis依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!--fastjson依賴--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.33</version> </dependency> <!--jwt依賴--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
2、添加Redis相關配置
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.TypeFactory; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationException; import com.alibaba.fastjson.parser.ParserConfig; import org.springframework.util.Assert; import java.nio.charset.Charset; /** * Redis使用FastJson序列化 * * @author sg */ public class FastJsonRedisSerializer<T> implements RedisSerializer<T> { public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); private Class<T> clazz; static { ParserConfig.getGlobalInstance().setAutoTypeSupport(true); } public FastJsonRedisSerializer(Class<T> clazz) { super(); this.clazz = clazz; } @Override public byte[] serialize(T t) throws SerializationException { if (t == null) { return new byte[0]; } return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); } @Override public T deserialize(byte[] bytes) throws SerializationException { if (bytes == null || bytes.length <= 0) { return null; } String str = new String(bytes, DEFAULT_CHARSET); return JSON.parseObject(str, clazz); } protected JavaType getJavaType(Class<?> clazz) { return TypeFactory.defaultInstance().constructType(clazz); } }
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { @Bean @SuppressWarnings(value = { "unchecked", "rawtypes" }) public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class); // 使用StringRedisSerializer來序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(serializer); // Hash的key也采用StringRedisSerializer的序列化方式 template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(serializer); template.afterPropertiesSet(); return template; } }
封裝返回的數(shù)據(jù)
import com.fasterxml.jackson.annotation.JsonInclude; @JsonInclude(JsonInclude.Include.NON_NULL) public class ResponseResult<T> { /** * 狀態(tài)碼 */ private Integer code; /** * 提示信息,如果有錯誤時,前端可以獲取該字段進行提示 */ private String msg; /** * 查詢到的結果數(shù)據(jù), */ private T data; public ResponseResult(Integer code, String msg) { this.code = code; this.msg = msg; } public ResponseResult(Integer code, T data) { this.code = code; this.data = data; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getData() { return data; } public void setData(T data) { this.data = data; } public ResponseResult(Integer code, String msg, T data) { this.code = code; this.msg = msg; this.data = data; } }
JWT工具類
import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; import java.util.Date; import java.util.UUID; /** * JWT工具類 */ public class JwtUtil { //有效期為 public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000 一個小時 //設置秘鑰明文 public static final String JWT_KEY = "sangeng"; public static String getUUID(){ String token = UUID.randomUUID().toString().replaceAll("-", ""); return token; } /** * 生成jtw * @param subject token中要存放的數(shù)據(jù)(json格式) * @return */ public static String createJWT(String subject) { JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 設置過期時間 return builder.compact(); } /** * 生成jtw * @param subject token中要存放的數(shù)據(jù)(json格式) * @param ttlMillis token超時時間 * @return */ public static String createJWT(String subject, Long ttlMillis) { JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 設置過期時間 return builder.compact(); } private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) { SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; SecretKey secretKey = generalKey(); long nowMillis = System.currentTimeMillis(); Date now = new Date(nowMillis); if(ttlMillis==null){ ttlMillis=JwtUtil.JWT_TTL; } long expMillis = nowMillis + ttlMillis; Date expDate = new Date(expMillis); return Jwts.builder() .setId(uuid) //唯一的ID .setSubject(subject) // 主題 可以是JSON數(shù)據(jù) .setIssuer("sg") // 簽發(fā)者 .setIssuedAt(now) // 簽發(fā)時間 .signWith(signatureAlgorithm, secretKey) //使用HS256對稱加密算法簽名, 第二個參數(shù)為秘鑰 .setExpiration(expDate); } /** * 創(chuàng)建token * @param id * @param subject * @param ttlMillis * @return */ public static String createJWT(String id, String subject, Long ttlMillis) { JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 設置過期時間 return builder.compact(); } public static void main(String[] args) throws Exception { String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjYWM2ZDVhZi1mNjVlLTQ0MDAtYjcxMi0zYWEwOGIyOTIwYjQiLCJzdWIiOiJzZyIsImlzcyI6InNnIiwiaWF0IjoxNjM4MTA2NzEyLCJleHAiOjE2MzgxMTAzMTJ9.JVsSbkP94wuczb4QryQbAke3ysBDIL5ou8fWsbt_ebg"; Claims claims = parseJWT(token); System.out.println(claims); } /** * 生成加密后的秘鑰 secretKey * @return */ public static SecretKey generalKey() { byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY); SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES"); return key; } /** * 解析 * * @param jwt * @return * @throws Exception */ public static Claims parseJWT(String jwt) throws Exception { SecretKey secretKey = generalKey(); return Jwts.parser() .setSigningKey(secretKey) .parseClaimsJws(jwt) .getBody(); } }
Redis工具類
import java.util.*; import java.util.concurrent.TimeUnit; @SuppressWarnings(value = { "unchecked", "rawtypes" }) @Component public class RedisCache { @Autowired public RedisTemplate redisTemplate; /** * 緩存基本的對象,Integer、String、實體類等 * * @param key 緩存的鍵值 * @param value 緩存的值 */ public <T> void setCacheObject(final String key, final T value) { redisTemplate.opsForValue().set(key, value); } /** * 緩存基本的對象,Integer、String、實體類等 * * @param key 緩存的鍵值 * @param value 緩存的值 * @param timeout 時間 * @param timeUnit 時間顆粒度 */ public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) { redisTemplate.opsForValue().set(key, value, timeout, timeUnit); } /** * 設置有效時間 * * @param key Redis鍵 * @param timeout 超時時間 * @return true=設置成功;false=設置失敗 */ public boolean expire(final String key, final long timeout) { return expire(key, timeout, TimeUnit.SECONDS); } /** * 設置有效時間 * * @param key Redis鍵 * @param timeout 超時時間 * @param unit 時間單位 * @return true=設置成功;false=設置失敗 */ public boolean expire(final String key, final long timeout, final TimeUnit unit) { return redisTemplate.expire(key, timeout, unit); } /** * 獲得緩存的基本對象。 * * @param key 緩存鍵值 * @return 緩存鍵值對應的數(shù)據(jù) */ public <T> T getCacheObject(final String key) { ValueOperations<String, T> operation = redisTemplate.opsForValue(); return operation.get(key); } /** * 刪除單個對象 * * @param key */ public boolean deleteObject(final String key) { return redisTemplate.delete(key); } /** * 刪除集合對象 * * @param collection 多個對象 * @return */ public long deleteObject(final Collection collection) { return redisTemplate.delete(collection); } /** * 緩存List數(shù)據(jù) * * @param key 緩存的鍵值 * @param dataList 待緩存的List數(shù)據(jù) * @return 緩存的對象 */ public <T> long setCacheList(final String key, final List<T> dataList) { Long count = redisTemplate.opsForList().rightPushAll(key, dataList); return count == null ? 0 : count; } /** * 獲得緩存的list對象 * * @param key 緩存的鍵值 * @return 緩存鍵值對應的數(shù)據(jù) */ public <T> List<T> getCacheList(final String key) { return redisTemplate.opsForList().range(key, 0, -1); } /** * 緩存Set * * @param key 緩存鍵值 * @param dataSet 緩存的數(shù)據(jù) * @return 緩存數(shù)據(jù)的對象 */ public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) { BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key); Iterator<T> it = dataSet.iterator(); while (it.hasNext()) { setOperation.add(it.next()); } return setOperation; } /** * 獲得緩存的set * * @param key * @return */ public <T> Set<T> getCacheSet(final String key) { return redisTemplate.opsForSet().members(key); } /** * 緩存Map * * @param key * @param dataMap */ public <T> void setCacheMap(final String key, final Map<String, T> dataMap) { if (dataMap != null) { redisTemplate.opsForHash().putAll(key, dataMap); } } /** * 獲得緩存的Map * * @param key * @return */ public <T> Map<String, T> getCacheMap(final String key) { return redisTemplate.opsForHash().entries(key); } /** * 往Hash中存入數(shù)據(jù) * * @param key Redis鍵 * @param hKey Hash鍵 * @param value 值 */ public <T> void setCacheMapValue(final String key, final String hKey, final T value) { redisTemplate.opsForHash().put(key, hKey, value); } /** * 獲取Hash中的數(shù)據(jù) * * @param key Redis鍵 * @param hKey Hash鍵 * @return Hash中的對象 */ public <T> T getCacheMapValue(final String key, final String hKey) { HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash(); return opsForHash.get(key, hKey); } /** * 刪除Hash中的數(shù)據(jù) * * @param key * @param hkey */ public void delCacheMapValue(final String key, final String hkey) { HashOperations hashOperations = redisTemplate.opsForHash(); hashOperations.delete(key, hkey); } /** * 獲取多個Hash中的數(shù)據(jù) * * @param key Redis鍵 * @param hKeys Hash鍵集合 * @return Hash對象集合 */ public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) { return redisTemplate.opsForHash().multiGet(key, hKeys); } /** * 獲得緩存的基本對象列表 * * @param pattern 字符串前綴 * @return 對象列表 */ public Collection<String> keys(final String pattern) { return redisTemplate.keys(pattern); } }
將字符串渲染到客戶端工具類
import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class WebUtils { /** * 將字符串渲染到客戶端 * * @param response 渲染對象 * @param string 待渲染的字符串 * @return null */ public static String renderString(HttpServletResponse response, String string) { try { response.setStatus(200); response.setContentType("application/json"); response.setCharacterEncoding("utf-8"); response.getWriter().print(string); } catch (IOException e) { e.printStackTrace(); } return null; } }
SQL語句創(chuàng)建用戶表
CREATE TABLE `sys_user` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵', `user_name` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT '用戶名', `nick_name` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT '昵稱', `password` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT '密碼', `status` CHAR(1) DEFAULT '0' COMMENT '賬號狀態(tài)(0正常 1停用)', `email` VARCHAR(64) DEFAULT NULL COMMENT '郵箱', `phonenumber` VARCHAR(32) DEFAULT NULL COMMENT '手機號', `sex` CHAR(1) DEFAULT NULL COMMENT '用戶性別(0男,1女,2未知)', `avatar` VARCHAR(128) DEFAULT NULL COMMENT '頭像', `user_type` CHAR(1) NOT NULL DEFAULT '1' COMMENT '用戶類型(0管理員,1普通用戶)', `create_by` BIGINT(20) DEFAULT NULL COMMENT '創(chuàng)建人的用戶id', `create_time` DATETIME DEFAULT NULL COMMENT '創(chuàng)建時間', `update_by` BIGINT(20) DEFAULT NULL COMMENT '更新人', `update_time` DATETIME DEFAULT NULL COMMENT '更新時間', `del_flag` INT(11) DEFAULT '0' COMMENT '刪除標志(0代表未刪除,1代表已刪除)', PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用戶表'
配置文件
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/你的數(shù)據(jù)庫名稱?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8 username: **** password: **** redis: # Redis服務器地址 host: 127.0.0.1 # Redis服務器連接端口 port: 6379 # Redis服務器連接密碼 password: # Redis數(shù)據(jù)庫索引 database: 3 # 連接超時時間(毫秒) timeout: 30000 lettuce: pool: max-active: 50 max-wait: -1 max-idle: 50 min-idle: 1
編碼實現(xiàn)
目錄結構
關于Email
的類不用管
配置類
RedisConfig類
package com.zzuli.common.config; import com.zzuli.common.utils.FastJsonRedisSerializer; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; public class RedisConfig { public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class); // 使用StringRedisSerializer來序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(serializer); // Hash的key也采用StringRedisSerializer的序列化方式 template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(serializer); template.afterPropertiesSet(); return template; } }
SecurityConfig
類
package com.zzuli.common.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; 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.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; /** * @author niuben */ @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { //創(chuàng)建BCryptPasswordEncoder注入容器 @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http //關閉csrf .csrf().disable() //不通過Session獲取SecurityContext .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() // 對于登錄接口 允許匿名訪問 .antMatchers("/user/login").anonymous() // 除上面外的所有請求全部需要鑒權認證 .anyRequest().authenticated(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } }
實體類User類
package com.zzuli.pojo; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.Date; /** * 用戶表(User)實體類 * * @author 三更 */ @Data @AllArgsConstructor @NoArgsConstructor @TableName("sys_user") //數(shù)據(jù)庫的用戶名名稱 public class User implements Serializable { private static final long serialVersionUID = -40356785423868312L; /** * 主鍵 */ @TableId private Long id; /** * 用戶名 */ private String userName; /** * 昵稱 */ private String nickName; /** * 密碼 */ private String password; /** * 賬號狀態(tài)(0正常 1停用) */ private String status; /** * 郵箱 */ private String email; /** * 手機號 */ private String phonenumber; /** * 用戶性別(0男,1女,2未知) */ private String sex; /** * 頭像 */ private String avatar; /** * 用戶類型(0管理員,1普通用戶) */ private String userType; /** * 創(chuàng)建人的用戶id */ private Long createBy; /** * 創(chuàng)建時間 */ private Date createTime; /** * 更新人 */ private Long updateBy; /** * 更新時間 */ private Date updateTime; /** * 刪除標志(0代表未刪除,1代表已刪除) */ private Integer delFlag; }
UserLogin
類
繼承UserDetails
package com.zzuli.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.util.Collection; /** * @author niuben */ @AllArgsConstructor @NoArgsConstructor @Data public class UserLogin implements UserDetails { private User user; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } @Override public String getPassword() { return user.getPassword(); } @Override public String getUsername() { return user.getUserName(); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
接口實現(xiàn)類LoginController
接口
package com.zzuli.controller; import com.zzuli.common.api.CommonResult; import com.zzuli.pojo.User; import com.zzuli.service.LoginService; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @author niuben */ @RestController public class LoginController { @Resource private LoginService loginService; @PostMapping("/user/login") public CommonResult<Object> login(@RequestBody User user){ CommonResult<Object> result = null; try { result = loginService.login(user); } catch (Exception e) { return CommonResult.success("賬戶或者密碼錯誤!"); } return result; } }
UserDetailsServiceImpl
實現(xiàn)類
package com.zzuli.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.zzuli.mapper.UserMapper; import com.zzuli.pojo.User; import com.zzuli.pojo.UserLogin; 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 javax.annotation.Resource; import java.util.Objects; /** * @author niuben */ @Service public class UserDetailsServiceImpl implements UserDetailsService { @Resource private UserMapper userMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //查詢用戶信息 LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>(); queryWrapper.eq(User::getUserName,username); User user = userMapper.selectOne(queryWrapper); //如果沒有查詢到用戶,就拋出異常 if(Objects.isNull(user)){ throw new RuntimeException("用戶名或者密碼錯誤!"); } //將數(shù)據(jù)封裝成UserDetails return new UserLogin(user); } }
LoginService
接口
package com.zzuli.service; import com.zzuli.common.api.CommonResult; import com.zzuli.pojo.User; /** * @author niuben */ public interface LoginService { CommonResult<Object> login(User user); }
LoginService
實現(xiàn)接口
package com.zzuli.service.impl; import com.zzuli.common.api.CommonResult; import com.zzuli.common.utils.JwtUtil; import com.zzuli.common.utils.RedisCache; import com.zzuli.pojo.User; import com.zzuli.pojo.UserLogin; import com.zzuli.service.LoginService; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.HashMap; import java.util.Map; import java.util.Objects; /** * @author niuben */ @Service public class LoginServiceImpl implements LoginService { @Resource private AuthenticationManager authenticationManager; @Resource private RedisCache redisCache; @Override public CommonResult<Object> login(User user) { //進行用戶認證 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword()); Authentication authenticate = authenticationManager.authenticate(authenticationToken); //認證未通過,給出提示 if(Objects.isNull(authenticate)){ throw new RuntimeException("登陸失敗!"); } //通過了,生成jwt UserLogin loginUser = (UserLogin) authenticate.getPrincipal(); String id = loginUser.getUser().getId().toString(); String jwt = JwtUtil.createJWT(id); Map<String,String> map = new HashMap<>(); map.put("token",jwt); //將用戶信息存入redis redisCache.setCacheObject("login"+id,loginUser); return CommonResult.success(map,"登陸成功!"); } }
UserMapper
類
package com.zzuli.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.zzuli.pojo.User; public interface UserMapper extends BaseMapper<User> { }
啟動類
package com.zzuli; import org.apache.ibatis.annotations.Mapper; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.zzuli.mapper") //mapper掃描器 public class AppleunlockManageApplication { public static void main(String[] args) { SpringApplication.run(AppleunlockManageApplication.class, args); } }
效果展示
注意:測試時要打開redis
,數(shù)據(jù)庫中的密碼必須是加密后的
可以使用一下方法進行加密,passwordEncoder
是SecurityConfig
中已經注入的
@Resource private PasswordEncoder passwordEncoder; String encode = passwordEncoder.encode("123456"); System.out.println(encode);
登錄接口測試
到此這篇關于Spring-Security實現(xiàn)登錄接口流程的文章就介紹到這了,更多相關Spring-Security登錄接口內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
使用Spring?Cloud?Stream處理Java消息流的操作流程
Spring?Cloud?Stream是一個用于構建消息驅動微服務的框架,能夠與各種消息中間件集成,如RabbitMQ、Kafka等,今天我們來探討如何使用Spring?Cloud?Stream來處理Java消息流,需要的朋友可以參考下2024-08-08Spring Security中的Servlet過濾器體系代碼分析
這篇文章主要介紹了Spring Security中的Servlet過濾器體系,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07Spring?cloud?Hystrix注解初始化源碼過程解讀
這篇文章主要為大家介紹了Hystrix初始化部分,我們從源碼的角度分析一下@EnableCircuitBreaker以及@HystrixCommand注解的初始化過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助2023-12-12