Sercurity + Auth2框架實現認證授權

SpringSecurity 是Spring家族的一員,是Spring家族提供的安全框架,提供認證和授權功能,最主要的是它提供了簡單的使用方式,同時又有很高的靈活性,簡單,靈活,強大。

主要的主要的幾個配置類

自定義Security的策略

AuthorizationServerConfigurerAdapter

例子如下:

@Configuration

@EnableAuthorizationServer

public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

@Override

? ? public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

? ? ? ? endpoints

? ? ? ? ? ? ? ? .authenticationManager(authenticationManager)

? ? ? ? ? ? ? ? .tokenGranter(new CompositeTokenGranter(getTokenGranters(endpoints)))

? ? ? ? ? ? ? ? .userDetailsService(userDetailsService)

? ? ? ? ? ? ? ? .tokenStore(tokenStore());

}

@Override

? ? public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

? ? ? ? //存放到db

? ? ? ? clients.jdbc(dataSource);

//? ? ? ? 存放到內存

? ? ? ? clients.inMemory()

? ? ? ? ? ? ? ? .withClient("webapp")

? ? ? ? ? ? ? ? .secret(pass)

? ? ? ? ? ? ? ? .scopes("server")

? ? ? ? ? ? ? ? .authorizedGrantTypes("password", "authorization_code", "refresh_token")

? ? ? ? ? ? ? ? .accessTokenValiditySeconds(24 * 60 * 60) //token有效期

? ? ? ? ? ? ? ? .refreshTokenValiditySeconds(24 * 60 * 60)

? ? ? ? ? ? ? ? .and().withClient("app")

? ? ? ? ? ? ? ? .secret(pass)

? ? ? ? ? ? ? ? .scopes("app")

? ? ? ? ? ? ? ? .authorizedGrantTypes("authorization_code", "refresh_token")

? ? ? ? ? ? ? ? .redirectUris("https://www.baidu.com/");

? ? }

/**

? ? * 填充認證方式

? ? * @param endpoints endpoints

? ? * @return list

? ? */

? ? private List<TokenGranter> getTokenGranters(AuthorizationServerEndpointsConfigurer endpoints) {

? ? ? ? AuthorizationServerTokenServices tokenServices = endpoints.getTokenServices();

? ? ? ? ClientDetailsService clientDetailsService = endpoints.getClientDetailsService();

? ? ? ? OAuth2RequestFactory oAuth2RequestFactory = endpoints.getOAuth2RequestFactory();

? ? ? ? AuthorizationCodeServices authorizationCodeServices = endpoints.getAuthorizationCodeServices();

? ? ? ? return new ArrayList<>(Arrays.asList(

? ? ? ? ? ? ? ? new RefreshTokenGranter(tokenServices, clientDetailsService, oAuth2RequestFactory),

? ? ? ? ? ? ? ? new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices, clientDetailsService,

? ? ? ? ? ? ? ? ? ? ? ? oAuth2RequestFactory),

? ? ? ? ? ? ? ? new ResourceOwnerPasswordTokenGranter(authenticationManager, endpoints.getTokenServices(),

? ? ? ? ? ? ? ? ? ? ? ? clientDetailsService, oAuth2RequestFactory),

? ? ? ? ? ? ? ? new MyAbstractTokenGranter(authenticationManager, tokenServices, clientDetailsService,

? ? ? ? ? ? ? ? ? ? ? ? oAuth2RequestFactory)));

? ? }

}


默認情況下spring?security?oauth?的http配置。

ResourceServerConfigurerAdapter:

例子如下

@Configuration

@EnableResourceServer

public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

? ? @Override

? ? public void configure(HttpSecurity http) throws Exception {

? ? ? ? http

? ? ? ? ? ? ? ? .csrf().disable()

? ? ? ? ? ? ? ? .exceptionHandling()

? ? ? ? ? ? ? ? .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))

? ? ? ? ? ? ? ? .and()

? ? ? ? ? ? ? ? .authorizeRequests()

? ? ? ? ? ? ? ? .antMatchers("/index/getUser").permitAll()

? ? ? ? ? ? ? ? .antMatchers("/user/getUserPassword").permitAll()

? ? ? ? ? ? ? ? .anyRequest().authenticated()

? ? ? ? ? ? ? ? .and()

? ? ? ? ? ? ? ? .httpBasic();

? ? }

}

WebSecurityConfigurerAdapter 類是個適配器, 需要配置的時候需要我們自己寫個配置類去繼承,根據自己的需求去進行配置即可WebSecurityConfigurerAdapter的配置攔截要優先于ResourceServerConfigurerAdapter,優先級高的http配置是可以覆蓋優先級低的配置的。

WebSecurityConfigurerAdapter

例子如下:

@Configuration

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {

? ? /**

? ? * 自定義實現用戶信息獲取

? ? *

? ? * @return

? ? */

? ? @Bean

? ? @Override

? ? public UserDetailsService userDetailsService() {

? ? ? ? return new MyUserDetailsServiceImpl();

? ? }

? ? /**

? ? * @param auth

? ? * @throws Exception

? ? */

? ? @Override

? ? protected void configure(AuthenticationManagerBuilder auth) throws Exception {

? ? ? ? auth.userDetailsService(userDetailsService())

? ? ? ? ? ? ? ? .passwordEncoder(passwordEncoder());

? ? }

? ? /**

? ? * @param http

? ? * @throws Exception

? ? */

? ? @Override

? ? protected void configure(HttpSecurity http) throws Exception {

? ? ? ? http.csrf().disable()

? ? ? ? ? ? ? ? .authorizeRequests().anyRequest().authenticated()

? ? ? ? ? ? ? ? .and()

? ? ? ? ? ? ? ? .httpBasic();

? ? }

? ? /**

? ? * 不定義沒有password grant_type

? ? */

? ? @Override

? ? @Bean

? ? public AuthenticationManager authenticationManagerBean() throws Exception {

? ? ? ? return super.authenticationManagerBean();

? ? }

? ? /**

? ? * 密碼解析器

? ? * @return PasswordEncoder

? ? */

? ? @Bean

? ? public PasswordEncoder passwordEncoder() {

? ? ? ? return new BCryptPasswordEncoder();

? ? }

}

繼承了抽象類 AbstractTokenGranter

AbstractTokenGranter

public class MyAbstractTokenGranter extends AbstractTokenGranter {

? ? @Autowired

? ? private UserInfo userInfo;

? ? @Autowired

? ? private RedisUtil redisUtil;

? ? private static final String GRANT_TYPE = "sms_cod";

? ? private final AuthenticationManager authenticationManager;

? ? public MyAbstractTokenGranter(AuthenticationManager authenticationManager,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AuthorizationServerTokenServices tokenServices,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ClientDetailsService clientDetailsService,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OAuth2RequestFactory requestFactory) {

? ? ? ? this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);

? ? }

? ? protected MyAbstractTokenGranter(AuthenticationManager authenticationManager,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AuthorizationServerTokenServices tokenServices,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ClientDetailsService clientDetailsService,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OAuth2RequestFactory requestFactory, String grantType) {

? ? ? ? super(tokenServices, clientDetailsService, requestFactory, grantType);

? ? ? ? this.authenticationManager = authenticationManager;

? ? }

? ? /**

? ? * 我們拿到的 token 終會過期的, 對應于刷新 token模式的 RefreshTokenGranter 則負責獲取新的 OAuth2AccessToken。

? ? *

? ? * @param client

? ? * @param tokenRequest

? ? * @return

? ? */

? ? @Override

? ? protected OAuth2AccessToken getAccessToken(ClientDetails client, TokenRequest tokenRequest) {

? ? ? ? // 傳入的參數需要有 refresh_token (DefaultOAuth2AccessToken 中有 refreshToken 字段)

? ? ? ? String refreshToken = tokenRequest.getRequestParameters().get("refresh_token");

? ? ? ? // 調用 tokenService 的刷新方法得到新的 OAuth2AccessToken

? ? ? ? return getTokenServices().refreshAccessToken(refreshToken, tokenRequest);

? ? }

? ? /**

? ? * 用戶攔截

? ? *

? ? * @param client? ? ? client

? ? * @param tokenRequest 請求的令牌

? ? * @return

? ? */

? ? @Override

? ? protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {

? ? ? ? Map<String, String> parameters = new LinkedHashMap<String, String>(tokenRequest.getRequestParameters());

? ? ? ? String username = parameters.get("username");

? ? ? ? String password = parameters.get("password");

? ? ? ? String mobile = parameters.get("mobile");

? ? ? ? //客戶端提交的驗證碼

? ? ? ? String smscode = parameters.get("sms_cod");

? ? ? ? String type = parameters.get("type");

? ? ? ? parameters.remove("password");

? ? ? ? //驗證用戶狀態(是否警用等)

//? ? ? ? UserInfo userInfo = new UserInfo();

//? ? ? ? userInfo.setMobile(mobile);

? ? ? ? // 驗證驗證碼

? ? ? ? //獲取服務中保存的用戶驗證碼

? ? ? ? String smsCheckCode = (String) redisUtil.get(userInfo.getMobile());

? ? ? ? if (StringUtils.isBlank(smsCheckCode)) {

? ? ? ? ? ? throw new InvalidGrantException("用戶沒有發送驗證碼");

? ? ? ? }

? ? ? ? if (!smscode.equals(smsCheckCode)) {

? ? ? ? ? ? throw new InvalidGrantException("驗證碼不正確");

? ? ? ? } else {

? ? ? ? ? ? //驗證通過后從緩存中移除驗證碼

? ? ? ? ? ? redisUtil.setRemove(userInfo.getMobile(), smsCheckCode);

? ? ? ? }

? ? ? ? if (username.isEmpty()) {

? ? ? ? ? ? throw new InvalidGrantException("用戶不存在");

? ? ? ? }

? ? ? ? Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password);

? ? ? ? ((AbstractAuthenticationToken) userAuth).setDetails(parameters);

? ? ? ? try {

? ? ? ? ? ? userAuth = authenticationManager.authenticate(userAuth);

? ? ? ? } catch (AccountStatusException ase) {

? ? ? ? ? ? //covers expired, locked, disabled cases (mentioned in section 5.2, draft 31)

? ? ? ? ? ? throw new InvalidGrantException(ase.getMessage());

? ? ? ? } catch (BadCredentialsException e) {

? ? ? ? ? ? // If the username/password are wrong the spec says we should send 400/invalid grant

? ? ? ? ? ? throw new InvalidGrantException(e.getMessage());

? ? ? ? }

? ? ? ? if (userAuth == null || !userAuth.isAuthenticated()) {

? ? ? ? ? ? throw new InvalidGrantException("Could not authenticate user: " + username);

? ? ? ? }

? ? ? ? OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);

? ? ? ? return new OAuth2Authentication(storedOAuth2Request, userAuth);

? ? }

核心依賴配置配置如下:

<dependency>

? ? ? ? ? ? <groupId>org.springframework.security.oauth</groupId>

? ? ? ? ? ? <artifactId>spring-security-oauth2</artifactId>

? ? ? ? ? ? <version>${oauth2.version}</version>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.cloud</groupId>

? ? ? ? ? ? <artifactId>spring-cloud-starter-security</artifactId>

? ? ? ? ? ? <exclusions>

? ? ? ? ? ? ? ? <!--舊版本 redis操作有問題-->

? ? ? ? ? ? ? ? <exclusion>

? ? ? ? ? ? ? ? ? ? <artifactId>spring-security-oauth2</artifactId>

? ? ? ? ? ? ? ? ? ? <groupId>org.springframework.security.oauth</groupId>

? ? ? ? ? ? ? ? </exclusion>

? ? ? ? ? ? </exclusions>

使用SpringSrcurity+Anut2根據token實現用戶密碼登錄

service層

/**

? ? * 根據用戶名查詢

? ? * @param userName 用戶名

? ? * @return 返回的路徑

? ? */

? ? UserInfo getUserInfoByName(@Param("userName") String userName);

Service層

@Service

public class MyUserDetailsServiceImpl implements UserDetailsService {

? ? @Autowired

? ? public PasswordEncoder passwordEncoder;

? ? @Resource

? ? private UserInfoService userInfoService;

? ? @Resource

? ? private UserInfoMapper userInfoMapper;

? ? @Override

? ? public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

? ? ? ? UserInfo userInfo = userInfoService.getUserInfoByName(username);

? ? ? ? if (userInfo == null){

? ? ? ? ? ? throw new UsernameNotFoundException(username);

? ? ? ? }

? ? ? ? return userInfo;

? ? }

Controlleer層

@RestController

@RequestMapping("/")

public class IndexController {

? ? /**

? ? * user

? ? * @param user user

? ? * @return Principal

? ? */

? ? @GetMapping(value = "/user")

? ? public Principal user(Principal user) {

? ? ? ? return user;

? ? }

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。