springboot后端如何實(shí)現(xiàn)攜帶token登陸
實(shí)現(xiàn)思路
使用oauth2+redis+mysql來(lái)完成登陸校驗(yàn),本案例使用oauth2簡(jiǎn)單的密碼模式來(lái)實(shí)現(xiàn)。
最終實(shí)現(xiàn)的效果為
- 登陸頁(yè)面不設(shè)置權(quán)限審核,用戶通過(guò)登陸界面登陸,輸入賬戶密碼,后端接收到賬戶密碼之后會(huì)去數(shù)據(jù)庫(kù)驗(yàn)證,如果驗(yàn)證通過(guò),則返回token給前端。
- 除了登陸頁(yè)面之外,其余的頁(yè)面訪問(wèn)的時(shí)候會(huì)進(jìn)行權(quán)限的鑒定,如果攜帶的token對(duì)應(yīng)用戶的權(quán)限不足或沒(méi)有攜帶token、攜帶了錯(cuò)誤的token,不允許訪問(wèn)。
- token具有時(shí)限,超時(shí)token會(huì)失效,可以通過(guò)refresh_token來(lái)刷新token的持續(xù)時(shí)間。
項(xiàng)目結(jié)構(gòu)
項(xiàng)目的結(jié)構(gòu)為
├─.idea │ └─dictionaries ├─log ├─src │ ├─main │ │ ├─java │ │ │ └─Rush │ │ │ ├─config │ │ │ ├─controller │ │ │ ├─mapper │ │ │ ├─pojo │ │ │ ├─service │ │ │ └─util │ │ └─resource │ └─test │ └─target
項(xiàng)目的重點(diǎn)其實(shí)也就在于config包內(nèi)
config包內(nèi)定義了4個(gè)類:
AuthorizationServerConfigResourceServerConfigWebSecurityConfigCORSFilter「額外針對(duì)OAuth跨域問(wèn)題」
除此之外,繼承了UserDetails接口的User類,繼承UserDetailsService類的UserService類也很關(guān)鍵。
除了這6個(gè)類之外,別的類和普通mybatis項(xiàng)目無(wú)異
AuthorizationServerConfig
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.web.bind.annotation.CrossOrigin;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig
extends AuthorizationServerConfigurerAdapter {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
RedisConnectionFactory redisConnectionFactory;
@Autowired
UserDetailsService userDetailsService;
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients)
throws Exception {
clients.inMemory()
.withClient("password")
.authorizedGrantTypes("password", "refresh_token")
.accessTokenValiditySeconds(1800)
.resourceIds("rid")
.scopes("all")
.secret("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.tokenStore(new RedisTokenStore(redisConnectionFactory))
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security)
throws Exception {
security.allowFormAuthenticationForClients();
}
}
ResourceServerConfig
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.web.bind.annotation.CrossOrigin;
@Configuration
@EnableResourceServer
public class ResourceServerConfig
extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources)
throws Exception {
resources.resourceId("rid").stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasAnyRole("user","admin")
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/home").permitAll()
.and()
.csrf().disable();
}
}WebSecurityConfig
import bocRush.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.authentication.AuthenticationManager;
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.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.CrossOrigin;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
? ? @Autowired
? ? UserService userService;
? ? @Bean
? ? @Override
? ? public AuthenticationManager authenticationManagerBean() throws Exception {
? ? ? ? return super.authenticationManagerBean();
? ? }
? ? @Bean
? ? @Override
? ? protected UserDetailsService userDetailsService() {
? ? ? ? return super.userDetailsService();
? ? }
? ? @Override
? ? protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// ? ? ? ?auth.inMemoryAuthentication()
// ? ? ? ? ? ? ? ?.withUser("admin")
// ? ? ? ? ? ? ? ?.password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq")
// ? ? ? ? ? ? ? ?.roles("admin")
// ? ? ? ? ? ? ? ?.and()
// ? ? ? ? ? ? ? ?.withUser("sang")
// ? ? ? ? ? ? ? ?.password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq")
// ? ? ? ? ? ? ? ?.roles("user");
? ? ? ? auth.userDetailsService(userService);
? ? }
? ? @Override
? ? protected void configure(HttpSecurity http) throws Exception {
? ? ? ? http.antMatcher("/oauth/**").authorizeRequests()
? ? ? ? ? ? ? ? .antMatchers("/oauth/**").permitAll()
? ? ? ? ? ? ? ? .and().cors()
? ? ? ? ? ? ? ? .and().csrf().disable();
? ? }
}CORSFilter
/**
?* Date ? : 2021/3/25 17:48
?* Author : nicolas
?*/
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*全局跨域配置*/
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
public class CORSFilter implements Filter {
? ? @Override
? ? public void init(FilterConfig filterConfig) throws ServletException {
? ? }
? ? @Override
? ? public void doFilter(ServletRequest servletRequest,
? ? ? ? ? ? ? ? ? ? ? ? ?ServletResponse servletResponse,
? ? ? ? ? ? ? ? ? ? ? ? ?FilterChain filterChain) throws IOException, ServletException {
? ? ? ? HttpServletRequest request = (HttpServletRequest) servletRequest;
? ? ? ? HttpServletResponse response = (HttpServletResponse) servletResponse;
? ? ? ? response.setHeader("Access-Control-Allow-Origin", "*");
? ? ? ? response.setHeader("Access-Control-Allow-Credentials", "true");
? ? ? ? response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE,PATCH,HEAD");
? ? ? ? response.setHeader("Access-Control-Allow-Max-Age", "3600");
? ? ? ? response.setHeader("Access-Control-Allow-Headers", "*");
? ? ? ? if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
? ? ? ? ? ? response.setStatus(HttpServletResponse.SC_OK);
? ? ? ? } else {
? ? ? ? ? ? filterChain.doFilter(servletRequest, servletResponse);
? ? ? ? }
? ? }
? ? @Override
? ? public void destroy() {
? ? }
}User
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 role : roles) {
? ? ? ? ? ? authorities.add(new SimpleGrantedAuthority("ROLE_" + role.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 !locked;
? ? }
? ? @Override
? ? public boolean isCredentialsNonExpired() {
? ? ? ? return true;
? ? }
? ? @Override
? ? public boolean isEnabled() {
? ? ? ? return enabled;
? ? }
? ? //省略getter/setter
? ? 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 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;
? ? }
}UserService
import bocRush.mapper.UserInfoMapper;
import bocRush.mapper.UserMapper;
import bocRush.pojo.User;
import bocRush.pojo.UserInfo;
import org.apache.ibatis.annotations.Param;
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.stereotype.Service;
@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()));
? ? ? ? //System.out.println(user.getRoles().get(1).getName() + " --- " + user.getUsername());
? ? ? ? return user;
? ? }
}對(duì)于接口的傳參數(shù)
獲取token
- 使用POST方法
http://localhost:8080/oauth/token?username=sang&password=123&grant_type=password&client_id=password&scope=all&client_secret=123
刷新token
- 使用POST方法
http://localhost:8080/oauth/token?grant_type=refresh_token&refresh_token=1a1c67a0-5f9b-49b1-9f95-dc7889c85cf5&client_id=password&client_secret=123
攜帶token訪問(wèn)資源
在url內(nèi)直接攜帶token
- GET方法
http://localhost:8080/user/hello?access_token=9bdde947-19b7-46fe-8fe0-0f2804150768
在header內(nèi)攜帶token
- GET方法
http://localhost:8080/admin/hello
------------Header----------------
Authorization : bearer 3929d92d-f5be-4b2d-9223-8b13e2412f14
Accept : application/json
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java獲取年月日(格式:xxxx年xx月xx日)的方法詳解
在開(kāi)發(fā)應(yīng)用程序時(shí),經(jīng)常需要獲取當(dāng)前的年、月、日,并以特定格式進(jìn)行展示或處理,本文將介紹如何獲取年月日,并將其格式化為“xxxx年xx月xx日”的形式,幫助你在應(yīng)用程序中處理日期信息,需要的朋友可以參考下2023-10-10
SpringBoot去除內(nèi)嵌tomcat的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot去除內(nèi)嵌tomcat的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
IDEA提示 add *** to custom tags問(wèn)題及解決
文章介紹了如何在文檔注釋中添加自定義注解(@xxx),并提供了添加和刪除注解的方法,總結(jié)了個(gè)人經(jīng)驗(yàn),希望對(duì)大家有所幫助2024-12-12
SpringBoot+Email發(fā)送郵件的實(shí)現(xiàn)示例
Spring?Boot提供了簡(jiǎn)單而強(qiáng)大的郵件發(fā)送功能,本文主要介紹了SpringBoot+Email發(fā)送郵件的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03
ireport數(shù)據(jù)表格報(bào)表的簡(jiǎn)單使用
這篇文章給大家介紹了如何畫一個(gè)報(bào)表模板,這里介紹下畫表格需要用到的組件,文中通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-10-10

