您的位置:首页 > 汽车 > 时评 > 长沙企业关键词优化服务价格_潍坊seo计费_百度问答官网_友情链接系统

长沙企业关键词优化服务价格_潍坊seo计费_百度问答官网_友情链接系统

2025/4/22 3:01:59 来源:https://blog.csdn.net/qq_44684238/article/details/147313174  浏览:    关键词:长沙企业关键词优化服务价格_潍坊seo计费_百度问答官网_友情链接系统
长沙企业关键词优化服务价格_潍坊seo计费_百度问答官网_友情链接系统

1. 导包

implementation("com.auth0:java-jwt:3.14.0")
implementation("org.springframework.boot:spring-boot-starter-security")

配置用户实体类


@Entity
@Table(name = "users")
data class User(@Id@GeneratedValue(strategy = GenerationType.IDENTITY)val uid: Long = 0,@Column(nullable = false, name = "username")val username: String = String.EMPTY_STRING,@Column(nullable = false, name = "password")val password: String = String.EMPTY_STRING,@Column(nullable = true)val email: String? = null,@Column(nullable = true)val phone: String? = null,
) {// 该方法作用是将实体类转为 UserUserDetails ,下文需要用到fun convertUserUserDetails(): UserDetailsImpl = UserDetailsImpl(this)class UserDetailsImpl(val user: User) : UserDetails {override fun getAuthorities(): MutableCollection<out GrantedAuthority> {return mutableListOf(SimpleGrantedAuthority("ROLE_USER"))}override fun getPassword(): String = user.passwordoverride fun getUsername(): String = user.username}
}

配置用户服务

@Service
class UserService(override val repository: UserRepository,
) : UserDetailsService {// ..... 其他方法// 需要继承 UserDetailsService  并重写该方法,用于查找用户// 通常 identifier 传入的 username,但是我的代码并非使用 username 登录,这里稍微替换下即可// 如果没有查找到 user 抛出异常// 方法返回需要 UserDetails 需要将 user 实体类转为 UserDetails override fun loadUserByUsername(identifier: String): UserDetailsImpl = when {identifier.isEmail -> findByEmail(identifier) ?: throw UsernameNotFoundException("Email not registered")identifier.isNumber -> findByPhone(identifier) ?: throw UsernameNotFoundException("Phone not registered")else -> throw UsernameNotFoundException("not found account $identifier")}.convertUserUserDetails()
}

配置 JWT 过滤器

// 主要方法为 isPass
// jwtConfig 是自己写的用于验证和签发 jwt,并存储 jwt 的设置,可以自己自行替换
class JwtTokenFilter(private val userService: UserService, private val jwtConfig: JwtConfig) : OncePerRequestFilter() {private fun isPass(request: ServletRequest, response: HttpServletResponse): Boolean {val jwt = getJwtString(request) ?: return falseval id = jwtConfig.decodeUserId(jwt) ?: return trueval user = userService.findByUid(id) ?: return trueval decodedJWT = jwtConfig.verifyLoginJwt(jwt, user) ?: return true// 主要逻辑:验证成功,在上下文中设置 AuthenticationTokensetAuthenticationToken(user)if (jwtConfig.autoRefresh) refresh(response, user, decodedJWT)return false}private fun refresh(response: ServletResponse,user: User,decodedJWT: DecodedJWT,): ResultLoginBean {if (decodedJWT.expiresAt.time - System.currentTimeMillis() <= 60 * 1000) {return ResultLoginBean.success(user, jwtConfig).apply {if (!jwtConfig.autoSetCookie) return@applyval cookie = Cookie(jwtConfig.cookieName, data?.token)cookie.isHttpOnly = truecookie.secure = falsecookie.maxAge = (jwtConfig.effectiveTime).toInt()cookie.path = "/"(response as HttpServletResponse).addCookie(cookie)}}return ResultLoginBean.success(ResultLoginBean.DataBean(decodedJWT.token))}private fun getJwtString(request: ServletRequest): String? {val value = getCookie(request)?.firstOrNull() { it.name == jwtConfig.cookieName }?.value ?: ""val value2 = getHeaders(request, "Authorization")?.replace(jwtConfig.headerPrefix, "") ?: ""return if (jwtConfig.fromCookie && value.isNotBlank()) {value} else if (jwtConfig.fromHeader && value2.isNotBlank()) {value2} else {null}}private fun getCookie(request: ServletRequest): Array<out Cookie>? {if (request is RequestFacade) return request.cookiesif (request is HttpServletRequest) return request.cookiesif (request is ServletRequestWrapper) {return getCookie(request.request)}return null}private fun getHeaders(request: ServletRequest, name: String): String? {if (request is RequestFacade) return request.getHeader(name)if (request is HttpServletRequest) return request.getHeader(name)if (request is ServletRequestWrapper) {return getHeaders(request.request, name)}return null}private fun setAuthenticationToken(user: User) {SecurityContextHolder.getContext().authentication = usernamePasswordAuthenticationToken(user)}// 这个类很长有用的不多,注意以下几点// 1. 认证成功,则在上下文中设置 usernamePasswordAuthenticationToken// 2. 认证失败,清空上下文// 3. 无论成功与失败都调用下一个过滤器,当然如果失败了你不调用下一个过滤器也行override fun doFilterInternal(request: HttpServletRequest,response: HttpServletResponse,filterChain: FilterChain,) {// 如果前端没有传入 token 则清理上下文if (isPass(request, response)) {SecurityContextHolder.clearContext()}// 无论Token 是否验证成功都传给下一个过滤器filterChain.doFilter(request, response)}}

配置 Spring Security

spring security 6 需要使用 filterChain 来配置认证链,并且 推荐使用 DSL 方式进行配置即Lambda方式

@Configuration
@EnableWebSecurity
class SpringSecurityConfig(private val userService: UserService, // 你的 User 服务用于查询用户的,但是需要实现 UserDetailsService 接口
){@Beanfun filterChain(http: HttpSecurity): SecurityFilterChain = http.run {// 由于使用 JWT 所以这里 关闭 sessionsessionsessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) }// 配置哪些请求需要验证或者放行authorizeHttpRequests {it.requestMatchers("/api/authority/**").permitAll()// 这种模糊匹配的范围很大需要在精确的路径之后配置,否则精确配置不生效it.requestMatchers("/api/**").authenticated() it.anyRequest().permitAll()}// 配置异常处理exceptionHandling {// 没有登录的错误it.authenticationEntryPoint { _, response, _ ->response.close(BaseBean(BaseBean.Code.LOGIN_EXPIRED))}// 没有权限的错误it.accessDeniedHandler { _, response, _ ->response.close(BaseBean(BaseBean.Code.PERMISSION_DENIED))}}// 添加 JWT 的认证过滤器到 UsernamePasswordAuthenticationFilter 链中addFilterBefore(JwtTokenFilter(userService, jwtConfig), UsernamePasswordAuthenticationFilter::class.java)isDisableFormLogin(false)httpBasic { it.disable() }rememberMe { it.disable() }// 生产下必须关闭 csrfcsrf { it.disable() }cors(Customizer.withDefaults())build()}
}/*** 两种登录方式,一种使用自定义登录接口,,一种使用框架本身的表单登录* 使用框架本身的表单登录会覆盖  /api/authority/login Controller* /api/authority/login Controller 实现不展出了,逻辑是验证用户名和密码之后返回 toekn(jwt)*/private fun HttpSecurity.isDisableFormLogin(isDisable: Boolean) {if (isDisable) {formLogin { it.disable() }return}formLogin {it.loginProcessingUrl("/api/authority/login") // 指定你的登录接口it.usernameParameter("identifier")it.passwordParameter("password")it.successHandler { request, response, auth ->// 这里将登录后 Token 发生回了前端// auth.principal as User.UserDetailsImpl 能转为 UserDetailsImpl  的愿意为,下面验证的时候传入的 UserDetailsImpl val user = (auth.principal as User.UserDetailsImpl).getUser()response.close(ResultLoginBean.success(user, jwtConfig, response))}it.failureHandler { request, response, exception ->response.close(BaseBean.fail("登录失败: ${exception.message}"))}}}/*** 身份校验机制、身份验证提供程序(isDisableFormLogin 中设置为 false)* 验证成功后会在认证链里面传递 UsernamePasswordAuthenticationToken */@Beanfun authenticationProvider(passwordEncoder: PasswordEncoder): AuthenticationProvider =object : AuthenticationProvider {override fun authenticate(authentication: Authentication): Authentication {val identifier = authentication.nameval password = authentication.credentials.toString()val user = userService.loadUserByUsername(identifier)if (passwordEncoder.matches(password, user.password)) {return usernamePasswordAuthenticationToken(user)} else {throw BadCredentialsException("The password is wrong")}}override fun supports(authentication: Class<*>): Boolean {return UsernamePasswordAuthenticationToken::class.java.isAssignableFrom(authentication)}}/*** 基于用户名和密码或使用用户名和密码进行身份验证*/@Beanfun authenticationManager(config: AuthenticationConfiguration): AuthenticationManager =config.getAuthenticationManager()// 配置拓展方法fun <T : Any> ServletResponse.close(data: BaseBean<T>) {this.contentType = "application/json;charset=UTF-8"this.writer.write(data.toString())this.writer.flush()this.writer.close()}@Bean(name = ["passwordEncoder", "bcryptPasswordEncoder"])fun passwordEncoder(): PasswordEncoder {return BCryptPasswordEncoder()}fun usernamePasswordAuthenticationToken(user: User): UsernamePasswordAuthenticationToken {return usernamePasswordAuthenticationToken(user.convertUserUserDetails())}fun usernamePasswordAuthenticationToken(user: User.UserDetailsImpl): UsernamePasswordAuthenticationToken {return UsernamePasswordAuthenticationToken(user, user.password,user.authorities)}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com